1. Ucitavanje podataka APR-a
Ucitacemo dva csv fajla, jedan sadrzi starije datume do 2013. godine dok drugi sadrzi novije datume od 2014. godine pa na dalje. Uvezivanje AOP-a po novom i starom kontnom okviru je vec uradjeno i sacuvano u data dva csv fajla. Sami fajlovi ne sadrze AOP-e!!! Razlog je što ne bi mogli da se spoje u jedan fajl budući da AOP-i po starom i novom kontnom okviru nisu mapirani jedana na jedan i samim tim ne bi mogli da se “nalepe” jedan na drugi u cilju dobijanja jednog data.frame-a jer bi imali razlicit broj AOP-a (citaj kolona), fajlovi medjutim sadrze proracunata finansijska racija. Fajlovi sadrze finansijska racija koja su sracunata iz premapiranih iz AOP-a dva kontna okvira (novi i stari kontni okvir). Za detaljniji pregled, uvid u pojedinacne AOP-e pogledati fajlove iz foldera ove analize, fajlovi ce se nalaziti u “~\Early warning\Bottom Up\Korak 3\Pokazatelji” gde ~ predstavlja adresu na kojoj je postavljen folder.
Dodatno pojasnjenje o toliko spominjanim AOP-ima:
U APR bazi su sve pozicije iz bilansa stanja, bilansa uspeha, tokova gotovine, statistickih podataka o preduzecu (statisticki aneks) tretirane kao AOP pozicije, tako na primer broj zaposlenih datog preduzeca mozemo naci u polju AOP 605 za taj maticni broj, ili na primer vrednost stalne imovine iz bilansa stanja se nalazi u polju AOP 001. Medjutim usled menjanja kontnog okvira novi AOP-i sada imaju 4 umesto 3 cifre tako da gore navedane dve varijable se sada nalaze pod AOP-ima 9005 i 0002 respektivno. Medjutim nemoguce je premapirati sve AOP-e po starom nacinu izvestavanja sa AOP-ima po novom nacinu izvestavanja jedan na jedan pa je samim tim bilo i nemoguce prikazati tabela sa varijablama koje ucestvuju u proracunu finansijskih racija, vec su samo prikazani finansijski raciji kao krajnji rezultat.
Cilj je spojiti ova dva csv fajla u jedan. Ucitamo finansijska racija do 2013. godine:
Pokazatelji_stari <- read_delim("C:/Users/milos.cipovic/Desktop/Projekti/Early warning/Razvojni folder/Bottom Up/Korak 3/Pokazatelji/Pokazatelji stari.csv",";", escape_double = FALSE, col_types = cols(Datum = col_date(format = "%m-%d-%Y")), locale = locale(encoding = "ASCII"), trim_ws = TRUE, progress =FALSE)
gc()
Ucitamo finansijska racija posle 2013. godine
Pokazatelji_novi <-
read_delim(
"C:/Users/milos.cipovic/Desktop/Projekti/Early warning/Razvojni folder/Bottom Up/Korak 3/Pokazatelji/Pokazatelji novi.csv",
";",
escape_double = FALSE,
col_types = cols(Datum = col_date(format = "%m-%d-%Y")),
locale = locale(encoding = "ASCII"),
trim_ws = TRUE,
progress =F
)
gc()
Spajamo tabele Pokazatelji_stari i Pokazatelji_novi u jednu tabelu, ove dve tabele su ustvari predstavljale proracunata finansijska racija. Tabele su dobijene prethodnom analitikom i obradom podataka u excelu jer nije bilo moguce drugacije.. Pokrećemo read_KA4_RK_data funkciju za pripremanje KA4 i RK izvestaja. Kreiranje NBS_data funkcije je vec ranije opisano u scriptu ‘~\Early warning\Bottom Up\Korak 4\Early warning\nbs_data_prep.R’ koji sadrzi sustinski isti kod koji i funkcija read_KA4_RK_data.
APR_data <- rbind.data.frame(Pokazatelji_stari, Pokazatelji_novi)
rm(Pokazatelji_stari , Pokazatelji_novi)
gc()
source("nbs_data_prep_function.R")
KA4_url = "C:/Users/milos.cipovic/Desktop/Baze podataka/K4 i APR i NPL/KA4_podaci.txt"
RK_url = "C:/Users/milos.cipovic/Desktop/Baze podataka/K4 i APR i NPL/RK_novi.txt"
NBS_data <- read_KA4_RK_data(KA4_url, RK_url, consequtive_difolt=F)
Spajamo APR i NBS podatke i izbacujemo kolonu NazivSektor jer pravi probleme pri eksportu. Postoji sifrovana verzija ove kolone tako da smo u redu, prezivecemo bez nje. Tako da sada imamo pocetnu tabelu sa podacima koje poseduje NBS o duznicima koji se nalaze u bazi APR-a. Od podataka koje poseduje NBS najveci znacaj nam predstavlja indikator difolta koji nam govori da li ce posmatrani duznik sa sracunatim finansijskim racijima iz APR baze otici u difolt za dve godine ili ne.
c = merge(
NBS_data,
APR_data,
by.x = c("MAT_BR_DUZNIKA", "DATUM.x"),
by.y = c("Jmb", "Datum")
)
#rm(APR_data,NBS_data)
c = as.data.table(c)
c[, NazivSektor := NULL]
Kao prvi korak u daljoj analizi potrebno je pre svega obratiti paznju na logicnost unesenih vrednosti kao i na nedostajuce vrednosti, tj. proracunati procenat nedostajucih vrednosti. Nelogicnosti je najlakse proveriti pregledom sumarnih statistika tako da ce nam sledeca tabela pomoci u tome.
2. Preliminarna analiza podataka
Tabela 1. prikazuje aritmeticku sredinu, trimovanu vrednost iste, zatim medijanu, standardnu devijaciju, treci i cetvrti statisticki moment, minimalnu i maksimalnu vrednost kao i u poslednjem redu procenat nedostajucih vrednosti. U toku pripreme podataka u excelu pojedini raciji nisu mogli biti sracunati usled nedostajanja AOP-a za datu opservaciju, posledicno racio date observacije ce imati vrednost ili #N/A ili #DIV/0!. Ove dve vrednosti cemo u nastavku tretirati kao nedostajuce jer one to u svojoj prirodi i jesu. Ovde smo ih zamenili nedostajucim NA vrednostima u R-u.
#zamenjujem #DIV/0! i #N/A sa difoltnom vrednosti za nedostajuce vrednosti u R-u
b <- c
b <- as.data.frame(b)
for (i in 21:50) {
temp <- b[, i]
temp[temp == "#N/A" | temp == "#DIV/0!"] <- NA
b[, i] <- temp
b[, i] <- as.numeric(b[, i])
}
#sklanjam nepotrebne tabele da oslobodim memoriju jer mora se...kao i svuda do sada
rm(temp,i,KA4_url,RK_url,read_KA4_RK_data,APR_data)
#kreiram duplikat tabele na kom cu da daljeradim i zadrzavam samo bitne kolone,
#tj. neke ce mi biti potrebne kasnije ali za njih sam siguran da su ok jer sam ih kreirao i vec proverio
#u proceduri kreiranja podataka iz bankarskog sektora
b <- data.table(b)
clean_b <- b[, c(1, 4, 2, 9, 5, 7, 14, 16:50)]
#kreiram funkciju za proracun summary statistika
my.summary <- function(x, arg=T){
x<-as.matrix(x)
n<-nrow(x)
data.frame(mean=mean(x, na.rm=arg),
Trimmed_mean=mean(x,trim = 0.1,na.rm=arg),
sd=sd(x, na.rm=arg),
median=median(x, na.rm=arg),
skewness=e1071::skewness(x,na.rm=arg),
kurtosis=e1071::kurtosis(x,na.rm=arg),
min=min(x, na.rm=arg),
max=max(x,na.rm=arg),
First_quartile=quantile(x,0.25,na.rm=arg),
Third_quartile=quantile(x,0.75,na.rm=arg),
n=length(x),
NAspercent=round(sum(as.numeric(is.na(x))/n)*100,1)
)
}
#kreiram sumarnu tabelu
summary_table1 <- sapply(clean_b[, 11:42], my.summary, arg = T)
#printujem je u notebook
tr_summary_table1 <- t(summary_table1)
formatRound(
datatable(tr_summary_table1, caption = "Tabela 1.:Sumarni prikaz",
filter = 'none'),
columns = colnames(tr_summary_table1)
)
2.1 Nelogicni unosi
U ovom koraku je potrebno pre svega pregledati kategoricke varijable za nelogicne unose, naime, primeceno je da varijabla koja bi trebalo da oznacava velicinu duznika i uzima vrednosti od 1 do 4 sadrzi vrednosti koje su znacajno vece, takodje, malo je verovatno da je prosecan broj zaposlenih iznosi 7613. Uvidom u podatke doslo se do zakljucka da su date nelogicnosti rezultat razlike u strukturi izvestaja finansijskih institucija i ostalih lica koja su duzna da podatke unose u APR bazu, tako da AOP 602 kod finansijskih institucija ne predstavlja sifru velicine, isto vazi i za polje koje oznacava sifru broja zaposlenih. Daljim uvidom dolazi se do jos nekih saznanja u konzistentnosti AOP-a 602 koji oznacava velicinu lica, naime, otkriveno je jos jedno polje u bazi koju NBS poseduje, a koje nosi informacije o velicini lica, ovo polje nema sifru AOP-a. Posle provere podataka koje posedujemo i njihovim uporedjivanjem sa vrednostima sa APR sajta opredelili smo se za AOP 602. Prethodno opisana dva polja su se u pojedinim slucajevima razlikovala, zbog toga je i izvrsena analiza. Naime, pomenuto polje koje se nalazi u pivot tabelama (nacin na koji NBS ima pristup APR bazi) je u odredjenom broju slucajeva prikazivalo podatke od prethodne godine. Ovo je slucaj samo sa starim nacinom izvestavanja, dakle do 2013. godine!
Nastavljamo sa analizom tako sto cemo izbaciti iz tabele observacije sa vrednostima u koloni Velicina vecim od 4 i manjim od 1 i ponovo pregledati strukturu sumarne tabele. Naknadno, izbacicemo sva lica koja ne pripadaju grupi “Privrednih drustava i zadruga” obzirom da narusavaju homogenost uzorka kao i da im AOP pozicije nisu mapirane kao Privrednim drustavima i zadrugama pa su samim tim te observacije i glavni uzrok nekonzistentnosti u podacima.
Uvidom u Tabelu 2. i polja Velicina i Broj zaposlenih vidimo da su srednja vrednost, minimum i maksimum u prihvatljivim granicama. Posmatranje ostalih varijabli bi zahtevalo detaljniju analizu svake od njih ponaosob. Ovaj korak ce biti uradjen kasnije u univariate analizi tako da ce sada biti preskocen.
#ucitavam unapred pripremljenu tabelu koja nam za posmatrani mb i godinu daje njegovu pripadnost odredjenom sektoru, tj. govori nam iz kojeg je finansijskog izvestaja data observacija u APR-u
gc()
used (Mb) gc trigger (Mb) max used (Mb)
Ncells 3162980 84.5 22333286 596.4 18586441 496.4
Vcells 16162926 123.4 100972256 770.4 126212344 963.0
Pravna_forma <-
read_delim(
"C:/Users/milos.cipovic/Desktop/Projekti/Early warning/Razvojni folder/Bottom Up/Korak 5/Pravna forma.csv",
"|",
escape_double = FALSE,
trim_ws = TRUE,
col_types = cols(Datum = col_date(format = "%Y")),
progress = FALSE
)
#merdzujem poidatke sa clean_b, tj. preciscavam clean_b tako sto posto merdzujem zadrzim samo one sa
#sa sifrom 14000 sto predstavlja "Privredna drustava i zadruge"
clean_b <-
merge(
clean_b,
Pravna_forma,
by.x = c("DATUM.x", "MAT_BR_DUZNIKA"),
by.y = c("Datum1", "Jmb")
)
clean_b <-
clean_b[Sifra == 1400][, c("Naziv", "Sifra", "NazivPravnogLica") := NULL]
#izbacim vrednosti velicina koje su vece od 4, double check inace ne bi smelo da smanji broj redova
clean_b <- clean_b[Velicina <= 4 & Velicina > 0]
#ponovo kreiram data.frame summary_table
summary_table <- sapply(clean_b[, 11:42], my.summary, arg = T)
#transponujem
tr_summary_table <- t(summary_table)
#printujem tabelu
formatRound(
datatable(
tr_summary_table,
caption = "Tabela 2.:Sumarni prikaz bez banaka i ostalih finansijskih institucija",
filter = 'none',
extensions = 'Buttons',
options = list(
pageLength=13,
dom = 'Bfrtip',
buttons = c(
'copy',
'csv',
'excel'
)
)
),
columns = colnames(tr_summary_table)
)
2.2 Nedostajuce vrednosti
Tretiranje nedostajucih vrednosti kao korak u razvoju modela nosi dodatnu tezinu imajuci u vidu da ce biti potrebno tretirati nedostajuce vrednosti i u procesu samog predvidjanja solventnosti banke (a to je krajnji cilj ove analize) posto je model evaluiran. Samim tim, uvidom u literaturu o najboljim praksama tretmana nedostajucih observacija odlucujemo se za sledeci postupak koji je predlozen u knjizi Developing, Validating and Using Internal Ratings:
- Red observacije se brise ukoliko nedostaje vise od 75% podataka u njemu
- Kolona varijable se brise ukoliko imaju vise od 10% nedostajucih vrednosti
- Ukoliko nedostaje manje od 10% observacije posmatrane varijable vrsi se imputacija (zamena) observacija medijanima varijabli. Na ovaj nacin se izbegava osetljivost na autlajere koju poseduje srednja vrednost. Pri cemu se medijana posebno proracunava za zdrave a posebno za duznike u statusu neizmirenja obaveza. Ovo, medjutim nije slucaj kod validacionog uzorka, kao takav on ne bi trebao da sadrzi nikakvu informaciju o tome da li ce posmatrani duznik u buducnosti prestati da izmiruje svoje obaveze, samim tim u validacionom uzorku kao vrednost inputacije koristimo medijanu komplet varijable, nezavisno od toga da li pripada solventnim ili nesolventnim duznicima.
- Indikatori se transformisu u kategoricke varijable ukoliko postoji apriori znanje o njihovom znacaju i ukoliko ne postoje proksi indikatori koji bi zamenili posmatrani indikator.
Varijable koje predstavljaju problem u smislu procenata nedostajanja su:
- Racio_novcane_likvidnosti_(Cash_ratio) - ova varijabla je na granici po gorenavedenim kriterijumima
- Racio_obrta_potrazivanja_od_kupaca
- Racio_obrta_poslovne_imovine
- Rast_EBITDA
- Stopa_prinosa_na_ukupna_sredstva_pre_oporezivanja - ova varijabla je na granici po gorenavedenim kriterijumima
- Rast_prihoda_od_prodaje
- Pokrice_neto_kamata
Zapazamo da se brisanje nedostajucih observacija preporucuje tek posto su ispunjeni odredjeni uslovi bez obzira na velicinu uzorka, brisanje nedostajucih observacija bi generalno trebalo da bude poslednja opcija pri ciscenju podataka.
Jos jedna cinjenica ce imati udeo u izboru varijabli. Pre svega cetiri pokazatelja u listi su dinamicki i prikazuju stopu rasta odredjene velicine, cime se gubi jedna (prva) godina observacija, samim tim ova cetiri pokazatelja ce u prvoj godini imati sve nedostajuce vrednosti. Navodimo ove racije:
- Racio obrta potraživanja od kupaca;
- Racio obrta poslovne imovine;
- Rast EBITDA;
- Rast prihoda od prodaje.
Odluka o brisanju ili zadrzavanju ovih varijabli ce prevashodno zavisiti od njihove diskriminativne moci pa zatim od gore navedenih kriterijuma. Dodatno pojasnjavamo da bi zadrzavanje ovih varijabli skratilo citav uzorak za prvu godinu observacija, pa ce i velicina uzorka biti presudan faktor.
Pre primene gore navedenih postupaka vazno je navesti da cemo mi raditi tri modela, u zavisnosti od velicine duznika. Sama podela ce biti izvrsena na osnovu varijable Velicina koja razvrstava lica prema unapred utvrdjenim kriterijumima APR-a videti APR/“Критеријуми за разврставање и граничне вредности за 2016. годину”. U cilju uzimanja u obzir velicine izlozenosti koristicemo i varijablu koja predsavlja udeo izlozenosti posmatranog duznika u kapitalu banke koja je prema njemu izlozena. Ova varijabla ce biti naknadno sracunata i ima za cilj da uzme u obzir razlicit tretman prema duzniku prema njegovoj velicini posmatrano sa stanovnistva banke. Buduci da su odredjeni duznici zaduzeni kod vise banaka posmatrace se samo one banke u kojima je dati duznik najvise zaduzen. Ovo je ujedno i rezultat ranije obrade podataka iz KA4 i RK obrasca (videti skript “~Early warning\nbs_data_prep.R”) gde su o ovim slucajevima visestruke izlozenosti sacuvane observacija kod banaka prema kojima poseduju najveca dugovanja. Pre pocetka univariate analize potrebno je proracunati vec spomenuti udeo izlozenosti posmatranog duznika u regulatornom kapitalu banke. To cemo uraditi tako sto cemo inportovati vec pripremljenu tabelu sa serijom vrednosti regulatornog kapitala banaka.
#ucitavam seriju re4gulatornog kapitala za banke
regulatory_capital <- read_delim(
"C:/Users/milos.cipovic/Desktop/Projekti/Early warning/Razvojni folder/Bottom Up/Korak 5/regulatory_capital.csv",
";",
escape_double = FALSE,
col_types = cols(Datum = col_date(format = "%d.%m.%Y")),
trim_ws = TRUE
)
#prilepljujem je za clean_b tabelu
clean_b <-
merge(
clean_b,
regulatory_capital,
by.x = c("DATUM.x", "MATICNI_BROJ.x"),
by.y = c("Datum", "MB")
)
#proracunavam udeo izlozenosti i odstranjujem kolone viska koje su dosle sa tabelom regulatory_capital
clean_b <-
clean_b[, udeo_u_kapitalu := (IZLOZENOST.x / Brojilac) * 1000]#skalirano zbog numerike
clean_b <- clean_b[, c("Brojilac", "Imenilac", "Pokazatelj") := NULL]
#cistim smece
rm(
b,
Pravna_forma,
regulatory_capital,
summary_table,
summary_table1,
tr_summary_table
)
gc()
used (Mb) gc trigger (Mb) max used (Mb)
Ncells 3163510 84.5 17866628 477.1 18586441 496.4
Vcells 13546759 103.4 80777804 616.3 126212344 963.0
Na kraju pogledajmo tabelu ciscenja podataka:
3. “Univariate” analiza
Do sada nismo jos uvek razmatrali kontinualne varijable, razlog je bio sto uzorak jos uvek nije bio podeljen na tri poduzorka u zavisnosti od velicine duznika. Pre pocetka univariate analize razdvojicemo uzorak na tri dela. Posebno ce se evaluirati modeli za mikro i mala, srednja i velika preduzeca. Takodje, tretman nedostajucih vrednosti je samo deskriptivno naveden u smislu metodoloskog pravca u kom ce se ici pri obradi. Sve ove analize i one koje slede ce se obaviti pojedinacno za svaku grupu duznika ponaosob. Pre nego sto se uzorak razdvoji, u ovoj sekciji, ukratko ce biti opisati raciji koji su korisceni, njihova ekonomska logika i ocekivanu vezu sa verovatnocom difolta, jer ce se isti set racija koristiti u sva tri slucaja. Po opisu racija, u nastavku ove sekcije, ce se ispitati broj nedostajucih vrednosti i njihov tretman, prisutnost autlajera i njihov tretman, radna hipoteza, monotonost, moc diskriminacije i korelacija za svaki od tri modela. Svi prethodno navedeni postupci imaju za cilj sto bolju pred selekciju varijabli pred ulzak u zavrsnu fazu multivariate analizu gde ce stepwise procedurom biti izabrani konacni modeli
3.1 Finansijski raciji, ekonomska logika i radna hipoteza
Kao polazna osnova poslo se od pet grupa pokazatelja koji bi, idealno, trebalo da nam daju informaciju o:
- Likvidnosti
- Solventnosti
- Profitabilnosti
- Poslovne aktivnosti
- Ostali pokazatelji koje je tesko svrstati
Pokazatelji, njihova pripadnost grupi i hipoteza ekonomske logicnosti njihove relacije sa verovatnocom nastupanja neizmirenja obaveza je prikazana u sledecoj tabeli:
3.2 “Univariate” analiza
Razdvajamo uzorak na tri podgrupe:
#kreiram tri nove tabele sa kojima dalje radim
small <- clean_b[Velicina <= 2, ]
medium <- clean_b[Velicina == 3, ]
large <- clean_b[Velicina == 4, ]
#brisem preostale medjukorake
rm(c, NBS_data)
gc()
used (Mb) gc trigger (Mb) max used (Mb)
Ncells 1547158 41.4 14293302 381.7 18586441 496.4
Vcells 9455548 72.2 64622243 493.1 126212344 963.0
Prvo ćemo detaljno analizirati velika preduzeca (podaci large) počevši od svih gore navedenih koraka u analizi, tako da će ovaj deo imati tri podgrupe, zavisno od same veličine dužnika. Samim tim i krećemo u detaljnu analizu sada…
Univariate analiza velikih preduzeća
Potrebno je pre svega razdvojiti uzorak na validacioni i estimacioni. U nacelu pravilo je da se uzorak deli na 70:30 na stranu estimacije, medjutim ukoliko kuburimo sa podacima Lemeshow u svom kursu o logistickoj regresiji argumentuje da je mnogo bitnije da imamo kompletniji uzorak za estimaciju, tako da cemo se voditi ovom logikom i u nasem slucaju.
Pa, pocnimo.
#izracunam broj redova
broj.red.lrge<-nrow(large)
broj.difolta.lrge<-sum(as.numeric(large$default.y==1))
procenat.difolta<-broj.difolta.lrge/broj.red.lrge
Dakle u najboljem slucaju, ne racunajuci missing value imamo 155 difolta, sto nam deluje kao jedva dovoljno, ukoliko bismo zadrzali 30% bili bismo na granici. Medjutim da bismo se osigurali zadrzacemo 75%, time opet imamo dovoljno difolta za validaciju (oko 40), ovde sam se vodio savetom profesora Lemeshow-a koji kaze da se u ovoj situaciji uvek pokusa zadovoljiti training sample. S druge strane racio nesolventnih u ukupnim duznicima moze imati razlicite vrednosti, tj. ne postoji konsenzus u literaturi o ovoj vrednosti. Ovde biramo da zadrzimo trenutan racio u uzorku tako da cemo uzeti 75% od (solventnih i nesolventnih) duznika zajedno i raditi estimaciju na njemu. Ovim postupkom smo izbegli postupak kalibracije jer smo u training uzorku zadrzali stvarnu frekvenciju defaulta, citaj, verovatnocu defoulta. Jedan problem koji se moze potencijalno javiti je validnost Hosmer–Lemeshow testa sa 40 difolta.
set.seed(60)
#zbog reprodukcije
sample.lrg <-
sample(broj.red.lrge, size = round(0.75 * broj.red.lrge, 0))
lrge.training <- large[sample.lrg, ]
lrge.test <- large[-sample.lrg, ]
Testiranje radne hipoteze, diskriminativnosti, korelacione matrice
Jos jednom cemo pregledati varijable:
#rpivotTable(lrge.training)
summary_table<-t(sapply(lrge.training[,11:43],my.summary,arg=T))
tr_summary_table<-t(summary_table)
formatRound(
datatable(
summary_table,caption = "Tabela 3.:Sumarni prikaz",
filter = 'none'
),
columns = colnames(summary_table)
)
Generalna preporuka je da se radna hipoteza testira pre tretmana nedostajućih vrednosti budući da će se nedostajuće vrednosti popunjavati uslovno od stanja solventnosti duznika. Samim tim ovde cemo kao prvi vid selekcije ispitati radnu hipotezu kako kontinualnih tako i kategorickih varijabli. Počećemo sa kontinualnim i analizu raditi u paru sa proverom diskriminativnosti varijabli. Još u Tabeli 3 vidimo velika odstupanja srednje vrednosti od medijane i trimovanog proseka, buduci da je prosek kao mera centralne tendencije osetljiva na autlajere odlucujemo se da posmatramo medijanu i trimovan prosek, samim tim mogucnost t testa otpada. Dalje, sledeci preporuke iz literature ovaj deo analize osloniti na posmatranje box plotova i bice dopunjen diskriminativnom analizom AUROC-a. Pri testiranju korelacija prag selekcije postavljamo na 0.5 i od dve biramo onu varijablu koja ima vecu diskriminacionu moc.
Kod kategorickih varijabli posmatracemo tabele frekvencija tamo gde to bude imalo smisla i sprovesti Chi-squared test. Ovom prilikom potrebno je i pregrupisati ove varijable tako da budu zadovoljeni kriterijumi:
- broj difolta po kategoriji kategoricke varijable mora biti minimum 5
- ukupan broj duznika po kategoriji kategoricke varijable mora biti veci od sto
- pravilo 1 u 10, za svakih 10 difolta možemo dodati jednu objašnjavajuću, ovo pravilo nam sluzi samo kao vodilja
- default rate mora biti statisticki razlicit od default rate-a ukupnog uzorka, inace se vrsi pregrupacija
- iako cemo ispitati hipotezu sagledavanjem tabela frekvencija, poslednju rec ce nam dati sami model i njegove p vrednosti, odnosno likelihood ratio test
Prvo pregledajmo samu distribuciju jos jednom, mada su neke stvari vec jasne iz Tabele 3 hajde ipak da pogledamo.
Prvo kreiramo funkciju za plotiranje: qq plota, box plota, poredjenja gustina verovatnoce (kernela empiriskih distribucija verovatnoce) i konacno za proveru diskriminacije ROC krive.
#delimo uzorak na kontinualne i kategoricke
lrge.training.continualne<-lrge.training[,c(7,6,11,13:43)]
lrge.training.kategoricke<-lrge.training[,c(7,8,9,10,12)]
lrge.test.continualne<-lrge.test[,c(7,6,11,13:43)]
lrge.test.kategoricke<-lrge.test[,c(7,8,9,10,12)]
ploting<-function(dataframe, predictor_col, default_column_col,n=3){
#transformacija podataka
dataframe=as.data.frame(dataframe)
data<-data.frame(predictor=dataframe[,predictor_col],
default_column=factor(dataframe[,default_column_col]))
data<-na.omit(data)
#density plot#####################
density<-ggplot(data, aes(predictor, fill=factor( default_column))) +
geom_density(alpha=.5) +
scale_fill_manual(values = c('#999999','#E69F00')) +
theme(legend.position = "none")+xlim(quantile(data$predictor,c(0.05,0.95),na.rm = T))
#boxplot############################
box_plot<-ggplot(data, aes(y=predictor, x= default_column, fill=default_column))+
geom_boxplot(alpha=0.5)
# compute lower and upper whiskers
ylim1 = boxplot.stats(data$predictor)$stats[c(1, 5)]
# scale y limits based on ylim1
box_plot = box_plot + coord_cartesian(ylim = ylim1*n)+
scale_fill_manual(values = c('#999999','#E69F00'))
#roc curve plot#######################
ROC_plot <-
ggplot(data, aes(m = predictor, d = as.numeric(default_column))) + geom_roc() +
geom_abline(intercept = 0,
slope = 1,
color = 'red')
result <- auc(data$default_column, data$predictor)
a = paste("Area under the curve:",
round(ci(result)[[1]], 3),
", ",
round(result, 3),
", ",
round(ci(result)[[3]], 3))
ROC_plot <- ROC_plot + labs(title = a)
#QQ plot
qs = seq(0.001, 0.999, by=0.001)
df.qs = data.frame(quantile.P = qs,
q.val.Normal = qnorm(qs,mean(data$predictor),sd(data$predictor)),
q.val.X = quantile(data$predictor,qs))
QQ_plot=ggplot(df.qs, aes(q.val.Normal, q.val.X))+
geom_point(col='#999999', cex=2)+
geom_line(col='#999999', size=0.75)+
geom_abline(position="identity")
plot_grid(density,box_plot,ROC_plot,QQ_plot,align = "h", ncol = 4)
}
Krećemo sa opisom svake varijable ponaosob:
Neprekidne promenljive:
Udeo ispravke u ukupnim kreditima
#definisem funkciju za plotovanje
ploting(lrge.training,6,7)
Ignoring unknown parameters: positionRemoved 63 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

Vidimo da distribucije odstupaju daleko od normalne, dalje preklapanje distribucija solventnih u nesolventnih duznika je razocaravajuce, postoji 7 autlajera koji imaju nelogicne vrednosti koji vuku poreklo iz rk obrasca. Iako box plot pokazuje odredjeni stepen diskriminacije u smislu da su solventni duznici manje ispravljeni od nesolventnih, generalno ROC kriva pokazuje da je diskriminacija marginalna iako je znacajna na nivou poverenaj od 95%, ipak, znacajnost je marginalna. Autlajeri ima ih, ima ih mnogo. Buduci da ce slicno biti i sa ostalim varijablama kreiramo taksativan opis u vidu buleta za svaku varijablu kao sto sledi za ovu:
- Radna hipoteza-nismo postavili radnu hipotezu za ovu varijablu
- Diskriminativnost -ne postoji na 95% sigurnosti
- autlajeri - naravno ima ih ima
- normalnost - ma da…
Broj zaposlenih
#definisem funkciju za plotovanje
ploting(lrge.training,11,7)
Ignoring unknown parameters: positionRemoved 125 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

- Radna hipoteza-nismo postavili radnu hipotezu za ovu varijablu
- Diskriminativnost - nema je
- autlajeri - naravno ima ih
- normalnost - ma da…
Rigorozni racio redukovane (monetarne) likvidnosti
#definisem funkciju za plotovanje
ploting(lrge.training,13,7)
Ignoring unknown parameters: positionRemoved 124 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

- Radna hipoteza-zadovoljena, veci difolt kod manjih vrednosti
- Diskriminativnost - ima na 95% znacajnosti
- autlajeri - naravno ima ih
- normalnost - ma da…
Racio novcane likvidnosti (Cash_ratio)
#definisem funkciju za plotovanje
ploting(lrge.training,14,7)
Ignoring unknown parameters: positionRemoved 114 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

- Radna hipoteza-zadovoljena, veci difolt kod manjih vrednosti
- Diskriminativnost - ima na 95% znacajnosti i obecava!!!
- autlajeri - naravno ima ih
- normalnost - ma da…
Opsti racio likvidnosti
#definisem funkciju za plotovanje
ploting(lrge.training,15,7)
Ignoring unknown parameters: positionRemoved 126 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

- Radna hipoteza-nezadovoljena, veci difolt kod vecih vrednosti
- Diskriminativnost - nema na 95% znacajnosti i to ti je!!!
- autlajeri - naravno ima ih
- normalnost - ma da…
Stepen_zaduzenosti
#definisem funkciju za plotovanje
ploting(lrge.training,16,7)
Ignoring unknown parameters: positionRemoved 120 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

- Radna hipoteza-zadovoljena, veci difolt kod vecih vrednosti
- Diskriminativnost - ima na 95% znacajnosti!!!
- autlajeri - naravno ima ih
- normalnost - ma da…
Interest Coverage Ratio
#definisem funkciju za plotovanje
ploting(lrge.training,17,7)
Ignoring unknown parameters: positionRemoved 126 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

- Radna hipoteza-zadovoljena, veci difolt kod manjih vrednosti
- Diskriminativnost - ima na 95% znacajnosti i ok je, moze da prodje, mada krivuda sto nije dobro!!!
- autlajeri - naravno ima ih
- normalnost - ma da, ali bar lici na nesto normalno…
Racio pokrica obrtne imovine
#definisem funkciju za plotovanje
ploting(lrge.training,18,7)
Ignoring unknown parameters: positionRemoved 126 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

- Radna hipoteza-zadovoljena, veci difolt kod manjih vrednosti
- Diskriminativnost - ima na 95% znacajnosti i ok je, solidno!!!
- autlajeri - naravno ima ih
- normalnost - ma da
Racio obrta potrazivanja od kupaca
#definisem funkciju za plotovanje
ploting(lrge.training,19,7)
Ignoring unknown parameters: positionRemoved 114 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

- Radna hipoteza-zadovoljena, veci difolt kod manjih vrednosti
- Diskriminativnost - nema je 95% znacajnosti
- autlajeri - naravno ima ih
- normalnost - ma da, vise kao \(\tilde\chi^2\)nost hihihi, kapiras hi kao hi distribucija :) …
Racio obrta poslovne imovine
#definisem funkciju za plotovanje
ploting(lrge.training,20,7)
Ignoring unknown parameters: positionRemoved 114 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

- Radna hipoteza-zadovoljena, veci difolt kod manjih vrednosti
- Diskriminativnost - ima na 95% znacajnosti i ok je, moze da prodje, mada krivuda sto nije dobro!!!
- autlajeri - naravno ima ih
- normalnost - ma da…
Gotovinski ciklus 1
#definisem funkciju za plotovanje
ploting(lrge.training,21,7)
Ignoring unknown parameters: positionRemoved 126 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

- Radna hipoteza-nezadovoljena, veci difolt kod manjih vrednosti, zasto pitam se
- Diskriminativnost - ima na 95% znacajnosti i ok je, moze da prodje, mada krivuda sto nije dobro!!!
- autlajeri - naravno ima ih
- normalnost - ma da…
Vreme vezivanja zaliha
#definisem funkciju za plotovanje
ploting(lrge.training,22,7)
Ignoring unknown parameters: positionRemoved 126 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

- Radna hipoteza-zadovoljena, veci difolt kod vecih vrednosti
- Diskriminativnost - nema na 95% znacajnosti
- autlajeri - naravno ima ih
- normalnost - ma da…
Vreme kreditiranja kupaca
#definisem funkciju za plotovanje
ploting(lrge.training,23,7)
Ignoring unknown parameters: positionRemoved 126 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

- Radna hipoteza-zadovoljena, veci difolt kod vecih vrednosti
- Diskriminativnost - nema na 95% znacajnosti
- autlajeri - naravno ima ih
- normalnost - ma da…
Vreme naplate potraživanja
#definisem funkciju za plotovanje
ploting(lrge.training,24,7)
Ignoring unknown parameters: positionRemoved 126 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

- Radna hipoteza-zadovoljena, veci difolt kod vecih vrednosti
- Diskriminativnost - ima na 95% znacajnosti
- autlajeri - naravno ima ih
- normalnost - ma da…
Vreme plaćanja dobavljačima
#definisem funkciju za plotovanje
ploting(lrge.training,25,7)
Ignoring unknown parameters: positionRemoved 126 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

- Radna hipoteza-nezadovoljena, veci difolt kod manjih vrednosti, ipak cemo je uzeti, jer može ekonomski da se objasni rezultat
- Diskriminativnost - ima na 95% znacajnosti suprotan znak, ono sto bi moglo praviti problem je promena diskriminativnosti kod poslednje cetvrtine distribucije
- autlajeri - naravno ima ih
- normalnost - ma da…
Asset turnover
#definisem funkciju za plotovanje
ploting(lrge.training,26,7)
Ignoring unknown parameters: positionRemoved 126 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

- Radna hipoteza-zadovoljena, veca verovatnoca difolta kod manje medijane
- Diskriminativnost - nema na 95% znacajnosti, ipak cemo je uzeti, zbog diskriminativnosti u manjim vrednostima
- autlajeri - naravno ima ih
- normalnost - ma da…
Rast EBITDA
#definisem funkciju za plotovanje
ploting(lrge.training,27,7)
Ignoring unknown parameters: positionRemoved 114 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

- Radna hipoteza-zadovoljena, veca verovatnoca difolta kod manje medijane
- Diskriminativnost - na granici na 95% znacajnosti, uzecemo, mada menja diskriminativnost, videcemo posle multivariata
- autlajeri - naravno ima ih
- normalnost - ma da…
Stopa prinosa na sopstveni kapital pre oporezivanja
#definisem funkciju za plotovanje
ploting(lrge.training,28,7)
Ignoring unknown parameters: positionRemoved 120 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

- Radna hipoteza-ne znam koji mu je djavo ali evo ovde cemo medijana zdravog je -90.6642634 a nesolventnog je -96.1808463 sto odgovara radnoj hipotezi
- Diskriminativnost - znacajno na 95% znacajnosti, uzecemo
- autlajeri - naravno ima ih
- normalnost - ma da…
Stopa prinosa na ukupna sredstva pre oporezivanja
#definisem funkciju za plotovanje
ploting(lrge.training,29,7)
Ignoring unknown parameters: positionRemoved 126 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

- Radna hipoteza-ne znam koji mu je djavo ali evo ovde cemo medijana zdravog je -97.142369 a nesolventnog je -99.5386016 sto odgovara radnoj hipotezi
- Diskriminativnost - znacajno na 95% znacajnosti, mua
- autlajeri - naravno ima ih
- normalnost - jedan od blizih…
Basic Earnings Power Ratio
#definisem funkciju za plotovanje
ploting(lrge.training,30,7)
Ignoring unknown parameters: positionRemoved 126 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

- Radna hipoteza-zadovoljena je, veci difolt sa manjom vrednoscu
- Diskriminativnost - ima na 95% znacajnosti, mua
- autlajeri - naravno ima ih
- normalnost - jook…
Rast prihoda od prodaje
#definisem funkciju za plotovanje
ploting(lrge.training,31,7)
Ignoring unknown parameters: positionRemoved 114 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

- Radna hipoteza-nezadovoljena je, nema vidljive razlike
- Diskriminativnost - nije znacajna na 95% znacajnosti, kandidat za kategoricku
- autlajeri - naravno ima ih
- normalnost - jook…
Pokriće neto kamata
#definisem funkciju za plotovanje
ploting(lrge.training,32,7)
Ignoring unknown parameters: positionRemoved 124 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

- Radna hipoteza-zadovoljena je mada nema vidljive razlike zbog autlajera
- Diskriminativnost - nije znacajna na 95% znacajnosti, medjutim ROC ima s oblik sto znaci da postoji diskriminativnost obrnutog smera na vecim i manjim vrednostima, medjutim ovo znaci i da odnos sa verovatnocom default-a nije monoton, kandidat za kategoricku
- autlajeri - naravno ima ih
- normalnost - jook…
Cena tuđih izvora sredstava
#definisem funkciju za plotovanje
ploting(lrge.training,33,7)
Ignoring unknown parameters: positionRemoved 126 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

- Radna hipoteza-zadovoljena je, nema vidljive razlike
- Diskriminativnost - nije znacajna na 95% znacajnosti, medjutim ROC ima s oblik sto znaci da postoji diskriminativnost obrnutog smera na vecim i manjim vrednostima, medjutim ovo znaci i da odnos sa verovatnocom default-a nije monoton
- autlajeri - naravno ima ih
- normalnost - jook…
T1
#definisem funkciju za plotovanje
ploting(lrge.training,34,7)
Ignoring unknown parameters: positionRemoved 126 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

- Radna hipoteza-zadovoljena je
- Diskriminativnost - znacajna na 95% znacajnosti, medjutim brine monotonost, moze da prodje
- autlajeri - naravno ima ih
- normalnost - jook…
T2
#definisem funkciju za plotovanje
ploting(lrge.training,35,7)
Ignoring unknown parameters: positionRemoved 63 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

- Radna hipoteza-zadovoljena je
- Diskriminativnost - znacajna na 95% znacajnosti
- autlajeri - naravno ima ih
- normalnost - jook…
T3
#definisem funkciju za plotovanje
ploting(lrge.training,36,7)
Ignoring unknown parameters: positionRemoved 126 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

- Radna hipoteza-zadovoljena je
- Diskriminativnost - znacajna na 95% znacajnosti
- autlajeri - naravno ima ih
- normalnost - jook…
T4
#definisem funkciju za plotovanje
ploting(lrge.training,37,7)
Ignoring unknown parameters: positionRemoved 126 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

- Radna hipoteza-zadovoljena je
- Diskriminativnost - masterpiece
- autlajeri - naravno ima ih
- normalnost - jook…
T5
#definisem funkciju za plotovanje
ploting(lrge.training,38,7)
Ignoring unknown parameters: positionRemoved 126 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

- Radna hipoteza-zadovoljena je
- Diskriminativnost - nema
- autlajeri - naravno ima ih
- normalnost - jook…
T21
#definisem funkciju za plotovanje
ploting(lrge.training,39,7)
Ignoring unknown parameters: positionRemoved 126 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

- Radna hipoteza-nezadovoljena
- Diskriminativnost - nema, za malo
- autlajeri - naravno ima ih
- normalnost - jook…
Altman Z-score 1
#definisem funkciju za plotovanje
ploting(lrge.training,40,7)
Ignoring unknown parameters: positionRemoved 126 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

- Radna hipoteza-zadovoljena je
- Diskriminativnost - masterpiece
- autlajeri - naravno ima ih
- normalnost - jook…
Altman Z-score 2
#definisem funkciju za plotovanje
ploting(lrge.training,41,7)
Ignoring unknown parameters: positionRemoved 126 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

- Radna hipoteza-zadovoljena je
- Diskriminativnost - masterpiece
- autlajeri - naravno ima ih
- normalnost - jook…
Altman Z-score 3
#definisem funkciju za plotovanje
ploting(lrge.training,42,7)
Ignoring unknown parameters: positionRemoved 126 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

- Radna hipoteza-zadovoljena je
- Diskriminativnost - masterpiece
- autlajeri - naravno ima ih
- normalnost - jook…
Udeo u kapitalu banke
#definisem funkciju za plotovanje
ploting(lrge.training,43,7)
Ignoring unknown parameters: positionRemoved 126 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

- Radna hipoteza-zadovoljena je, veci udeo losiji su u proseku
- Diskriminativnost - za vece vrednosti da
- autlajeri - naravno ima ih
- normalnost - jook…
Korelaciona matrica
Kao dodatni kriterijum selekcije uzimamo i korelacionu matricu. Vodicemo se pre svega diskriminativnom moci koju posmatramo prema AUROC vrednosti kao prvim kriterijumom pri izboru izmedju dve varijable sa velikim stepenom korelacije.
U tabeli 5. ispod vidimo da najvecu diskriminacionu moc poseduje varijabla T14 odmah iza koje je ALtman 1.
#proracun
cor=cor(lrge.training.continualne[,c(-1,-31,-32,-33)], use = "complete.obs")
#dodajemo AUROC kao dodatnu kolonu pored varijable
corr_summary<-function (predictor){
response=factor(lrge.training.continualne[[1]])
suppressMessages(auc(response, as.numeric(predictor)))
}
auc_sumarno<-sapply(lrge.training.continualne[,c(-1,-31,-32,-33)], corr_summary)
kor_diskr<-(cbind(auc_sumarno,cor))
formatRound(
datatable(
kor_diskr,caption = "Tabela 5.:Sumarni prikaz",
filter = 'none'
),
columns = colnames(kor_diskr)
)
Ovde kreiram funkciju koja ce da filtrira varijable po kriterijumu korelacije. Naime, po ugledu na kao kriterijum granice koeficijenta korelacije preko koje ne bismo smeli prelaziti uzecemo vrednost od 0.5 koji ce u sprezi sa AUROC vrednosti selektirati jednu od dve varijable. Konacan izbor varijabli se vidi u korelacionoj tabeli ispod.
#assuming that table is n x (n+1) matrix where first column is AUROC value and the rest n x n is correlation matrix
corr_ellimination<-function(table1, ro=0.5){
table=table1
AUROC<-table[,1]
table<-table[order(table[,1],decreasing = T),][,-1]
table.temp=as.data.frame(table)
for(i in 1:ncol(table)){#kolona
for(j in 1:nrow(table)){#red
#browser()
if(abs(table[i,j])>ro & abs(table[i,j])<1){
row.name=rownames(table)[i]
if(sum(row.name==colnames(table.temp))==0) next
col.name=colnames(table)[j]
table.temp=table.temp[,col.name!=colnames(table.temp)]
table.temp=table.temp[col.name!=row.names(table.temp),]
}
}
}
AUROC=AUROC[rownames(table.temp)]
table.temp=cbind(AUROC,table.temp)
table.temp<-table.temp[AUROC>0.55,]
table.temp<-table.temp[,rownames(table.temp)]
table.temp[order(rownames(table.temp)),order(colnames(table.temp))]
AUROC=AUROC[rownames(table.temp)]
table.temp=cbind(AUROC,table.temp)
}
clean_cor<-corr_ellimination(kor_diskr)
knitr::kable(clean_cor, caption = "Tabela 6. skracena korelaciona tabela koja sadrzi varijable nad kojima ce se vrsiti dalja analiza")
| T14 |
0.6930996 |
1.0000000 |
0.2380564 |
0.0861365 |
-0.0492862 |
0.0279108 |
0.0528058 |
-0.0924748 |
-0.0132031 |
0.0125315 |
0.0152887 |
0.4168406 |
-0.1516384 |
0.0558360 |
-0.0844406 |
-0.0054643 |
0.0118250 |
-0.1011643 |
| Racio_novcane_likvidnosti_(Cash_ratio) |
0.6874731 |
0.2380564 |
1.0000000 |
0.1759795 |
-0.0344113 |
0.0701974 |
0.0620004 |
-0.1533594 |
-0.0008854 |
0.0106273 |
-0.0354183 |
0.3810735 |
-0.0267154 |
0.1808397 |
-0.0718441 |
-0.0419165 |
0.0142587 |
0.0995163 |
| Stopa_prinosa_na_ukupna_sredstva_pre_oporezivanja |
0.6688459 |
0.0861365 |
0.1759795 |
1.0000000 |
-0.0529346 |
0.1277511 |
0.1320325 |
-0.1426838 |
0.0324431 |
0.2194009 |
-0.0583805 |
0.1852934 |
0.3427016 |
0.3524184 |
-0.0880921 |
-0.1147123 |
0.2206145 |
0.1758942 |
| Stepen_zaduzenosti |
0.6497292 |
-0.0492862 |
-0.0344113 |
-0.0529346 |
1.0000000 |
-0.0090003 |
0.0001976 |
0.0854998 |
-0.0070604 |
-0.0146694 |
-0.0089752 |
-0.0267447 |
0.0458866 |
-0.0274399 |
0.0305530 |
-0.0173417 |
0.0006459 |
0.0528638 |
| Racio_pokrica_obrtne_imovine |
0.6384214 |
0.0279108 |
0.0701974 |
0.1277511 |
-0.0090003 |
1.0000000 |
0.0688290 |
0.0090351 |
-0.1150341 |
0.0364006 |
0.1176060 |
0.1870060 |
0.0951495 |
0.0880883 |
-0.0747342 |
-0.2800573 |
0.0164206 |
0.1993162 |
| Gotovinski_ciklus_1 |
0.6293838 |
0.0528058 |
0.0620004 |
0.1320325 |
0.0001976 |
0.0688290 |
1.0000000 |
-0.0001707 |
-0.3308074 |
0.0268798 |
-0.4595382 |
0.0517380 |
0.0901639 |
0.0508694 |
0.0523599 |
-0.2583952 |
0.0290077 |
-0.1819115 |
| Cena_tudjih_izvora_sredstava |
0.6209256 |
-0.0924748 |
-0.1533594 |
-0.1426838 |
0.0854998 |
0.0090351 |
-0.0001707 |
1.0000000 |
-0.0231550 |
-0.0157811 |
0.0317831 |
-0.0514815 |
-0.1306944 |
-0.0442208 |
0.0891322 |
0.0013485 |
-0.0565529 |
0.0813129 |
| Vreme_placanja_dobavljacima |
0.6062135 |
-0.0132031 |
-0.0008854 |
0.0324431 |
-0.0070604 |
-0.1150341 |
-0.3308074 |
-0.0231550 |
1.0000000 |
0.0035517 |
0.2513761 |
-0.0089706 |
-0.0478035 |
-0.0074010 |
-0.0103817 |
0.1725755 |
-0.0021802 |
0.0575137 |
| Stopa_prinosa_na_sopstveni_kapital_pre_oporezivanja |
0.6013182 |
0.0125315 |
0.0106273 |
0.2194009 |
-0.0146694 |
0.0364006 |
0.0268798 |
-0.0157811 |
0.0035517 |
1.0000000 |
-0.0039753 |
0.0166355 |
0.0736215 |
0.1062286 |
-0.0378999 |
-0.0171189 |
0.0559764 |
0.0623044 |
| Vreme_naplate_potrazivanja |
0.5968830 |
0.0152887 |
-0.0354183 |
-0.0583805 |
-0.0089752 |
0.1176060 |
-0.4595382 |
0.0317831 |
0.2513761 |
-0.0039753 |
1.0000000 |
0.1537135 |
-0.1261463 |
-0.0037859 |
-0.0047127 |
0.2907848 |
0.0046339 |
0.1520589 |
| Rigorozni_racio_redukovane_(monetarne)_likvidnosti |
0.5891707 |
0.4168406 |
0.3810735 |
0.1852934 |
-0.0267447 |
0.1870060 |
0.0517380 |
-0.0514815 |
-0.0089706 |
0.0166355 |
0.1537135 |
1.0000000 |
-0.0349812 |
0.0971327 |
-0.0877178 |
0.0745876 |
0.0245291 |
0.3011249 |
| Racio_obrta_poslovne_imovine |
0.5872213 |
-0.1516384 |
-0.0267154 |
0.3427016 |
0.0458866 |
0.0951495 |
0.0901639 |
-0.1306944 |
-0.0478035 |
0.0736215 |
-0.1261463 |
-0.0349812 |
1.0000000 |
-0.0113001 |
-0.0900542 |
-0.1675202 |
0.0577446 |
0.1696654 |
| Racio_pokrica_kamata_zaradom_pre_kamata_i_poreza_(Interest_Coverage_Ratio) |
0.5733705 |
0.0558360 |
0.1808397 |
0.3524184 |
-0.0274399 |
0.0880883 |
0.0508694 |
-0.0442208 |
-0.0074010 |
0.1062286 |
-0.0037859 |
0.0971327 |
-0.0113001 |
1.0000000 |
-0.0070101 |
-0.0461001 |
0.1114824 |
0.0148283 |
| udeo_u_kapitalu |
0.5680543 |
-0.0844406 |
-0.0718441 |
-0.0880921 |
0.0305530 |
-0.0747342 |
0.0523599 |
0.0891322 |
-0.0103817 |
-0.0378999 |
-0.0047127 |
-0.0877178 |
-0.0900542 |
-0.0070101 |
1.0000000 |
0.0771957 |
-0.0118592 |
-0.0744592 |
| Vreme_kreditiranja_kupaca |
0.5599333 |
-0.0054643 |
-0.0419165 |
-0.1147123 |
-0.0173417 |
-0.2800573 |
-0.2583952 |
0.0013485 |
0.1725755 |
-0.0171189 |
0.2907848 |
0.0745876 |
-0.1675202 |
-0.0461001 |
0.0771957 |
1.0000000 |
0.0022102 |
0.1150678 |
| Rast_EBITDA |
0.5587844 |
0.0118250 |
0.0142587 |
0.2206145 |
0.0006459 |
0.0164206 |
0.0290077 |
-0.0565529 |
-0.0021802 |
0.0559764 |
0.0046339 |
0.0245291 |
0.0577446 |
0.1114824 |
-0.0118592 |
0.0022102 |
1.0000000 |
0.0318944 |
| T21 |
0.5514432 |
-0.1011643 |
0.0995163 |
0.1758942 |
0.0528638 |
0.1993162 |
-0.1819115 |
0.0813129 |
0.0575137 |
0.0623044 |
0.1520589 |
0.3011249 |
0.1696654 |
0.0148283 |
-0.0744592 |
0.1150678 |
0.0318944 |
1.0000000 |
Da sumiramo, do sada smo kod kontinualnih, pregledali diskriminativnost. Generalno preporucuje da se odradi univariate logisticka pa njena diskriminativnost testira. Medjutim ovde smo pratili gde smo posmatrali diskriminativnost samih varijabli. Dalje, postoji par varijabli koje bismo mogli da transformisemo u kategoricke, sto je pozeljno.
Osim testiranja monotonosti hipoteze, negde se testira i postojanje linearne zavisnost izmedju logaritma empirijskih sansi i varijabli i istovremeno se transformisu varijable. prikazuju postupak transformacije ali i upozoravaju na opasnost od data.mining-a, i takodje primenjuju istovetan postupak. Mi cemo ovde koristiti postupak opisan u za par varijabli koje nisu pokazale monotonu zavisnost sa hipotezom, ukoliko nuzda natera, ali samo tada, transformisacemo sve kontinualne varijable. Za sada cemo ovaj postupak primeniti na varijablama Pokriće neto kamata, Asset turnover. Varijabla koju cemo pretvoriti u kategoricku je Udeo u kapitalu banke. Dinamicke varijable Rast EBITDA i Racio obrta poslovne imovine nemaju neku previse znacajnu diskriminativnu moc da bi se opravdalo skracenje citave serije uzorka, tako da ce se tretirati kao da su otpale u univariate analysis usled velikog broja nedostajucih vrednosti. Napravicemo jedan izuzetak kada budemo primenili pravilo odstranjivanja varijabli usled nedostajucih vrednosti, a to je varijabla koja je na granici, Cash_ratio jer je pokazala veliku diskrimacionu moc. Diskriminacionu moc gledamo po znacajnosti intervala poverenja od 95%, koji se kod funkcije u R-u racuna bootstrapovanjem. Generalno, vrednosti AUROC-a u vecim uzorcima koje imaju vrednosti vece od 55 se mogu smatrati znacajnim.
Pa hajde da krenemo sa gore navedenim. Takodje, videh da je mozda broj zaposlenih bilo potrebno rtacunati prema aktivi kao racio, ali to mi ranije nije palo na pamet, mada ne mislim da bi imalo znacajnih promena, eventualno, varijabla koja bi imala smisla je procentualna promena ove varijable, što bi, opet, zahtevalo gubljenje prve godine observacija samo zbog nje, jer se druge dinamicke varijable nisu pokazale kao dovoljno diskriminativno znacajne.
Dodatno o dinamickim varijablama, u buducim vezbama, predlazem da se skroz izbace iz selekcije iz razloga sto nisu monotone, naime, buduci da ove varijable mogu uzimati kako negativne tako i pozitivne vrednosti. Primera radi, moguc je sledeci slucaj, recimo da imamo dva preduzeca \(X^{[1]}\) i \(X^{[2]}\), u roku od dve godine oni su ostvarili sledece vrednosti nekog racija koji je obrnuto povezan sa difoltom (veci racio-manji PD):
\[ t:X_{t}^{[1]}=-0.5, X_{t}^{[2]}=0.7 \\ t+1:X_{t+1}^{[1]}=-0.9, X_{t+1}^{[2]}=0.9 \]
Tako da ukoliko sada izracunamo rast ovog racija za oba preduzeca dobijamo:
\[R_{x^{[1]}}=\frac{X_{t+1}^{[1]}}{X_{t}^{[1]}}-1=80 \%\\ R_{x^{[2]}}=\frac{X_{t+1}^{[2]}}{X_{t}^{[2]}}-1=28\% \]
, sto bi znacilo da preduzece 1 ima bolji PD od preduzeca 2 po pocetnoj hipotezi, a to ne moze biti jer je pozicija preduzeca 1 od starta bila losija i jos se pogorsala u sledecih godinu dana. Ovo je glavni razlog zbog koga, verovatno, ovakve varijable nisu pokazale jaku diskriminativnu moc. Kada se odlucimo u buducnosti za proracun rasta kao potencijalnu varijablu, potrebno je da on pre svega bude racunat na monotonim varijablama, koje ne menjaju znak!
Nastavljamo:
Tretman problematicnih varijabli
Ovako, generalno, ono sto nismo (nismo hteli komentarisati) komentarisali su simetricnosti varijabli. Pozitivno asimetricno je bar pola posmatranih varijabli tako da bi valjala neka vrsta logaritmovane transformacije uz vodjenje racuna o negativnim vrednostima (na primer transformacija tipa: \(\log(var + \min(var) + 1))\) bi se pobrinula za negativne vrednosti. Box Za negativnu asimetricnost bi koristili eventualno eksponencijalnu transformaciju. Videcemo posle prvog stepwisea i AUROC-a.
Ipak, ovde cemo se koncentrisati na par prethodno napomenutih varijabli.
Pokriće neto kamata
Prvo cemo podeliti varijablu na n intervala. Za optimalan broj intervala mozemo iskoristiti drugu funkciju koja ima algoritam koji bira broj intervala od 10 do 20 na osnovu odredjenih kriterijuma, vidi help funkcije dole.
#kreiram tabelu od pokrica neto kamata i indikatora default-a
data<-lrge.training[,c("default.y","Pokrice_neto_kamata")]
IV <- create_infotables(data=data,
y="default.y",
parallel=FALSE)
IV_Value = data.frame(IV$Summary)
IV_Value
IV$Tables
$Pokrice_neto_kamata
plot_infotables(IV,"Pokrice_neto_kamata")

Dakle optimum je 10, imajuci u obzir nedostajuce vrednosti kao 11 kategoriju. Sada racunamo fiting funkciju transformacije. Generalno, mogli bismo podeliti varijablu u 8 kategorickih, ali ja bih izbegao to. Hajde prvo da vidimo empirijsku distribuciju, pa da fitujemo.
#izracunam medijanu po svakom binu
#ovo je ujedno i prvi put da koristim listu u R-u
calibrate_parameters=function(tabela, varijabla, default.varijabla,
broj_binova=8,
outlier.quant=c(0.99,0.01)){
tabela$id<-1:nrow(tabela)
#provera da li je clasa tabele data.table objekat
if(!is.data.table(tabela)) tabela=as.data.table(tabela)
#mora ovako da bi se u funkciji pozvao naziv kasnije u eval funkciji, bag u data.table koji se ovako prevazilazi
varijabla=as.name(varijabla)
default.varijabla=as.name(default.varijabla)
############################################################################################
# kontinualna transformacija #
############################################################################################
#################################Log odds transformacija##################################
#kreiram kategoricku varijablu-kolonu u tabeli koja nam govori kojem quantilu, decilu.. (zavisno od broja binova) pripada data observacija varijable
tabela[,varijabla_Bin:=quantcut(
tabela[,eval(varijabla)],
q = seq(0,1,by = 1/broj_binova)
)
]
#kreiram tabelu medijana sa odgovarajucim pdjevima
temp_data<-na.omit(
tabela[,.(prob=sum(eval(default.varijabla))/(.N),
medians = median(eval(varijabla))),
by = varijabla_Bin]
)[order(medians)]
#fitujem funkciju na medijane prema pdjevima
loes_fit<-loess(prob~medians,data=temp_data )
y<-tabela[,eval(varijabla)]
#sredjujem autljere pre forecasta
ubound<-quantile(x = y, probs = outlier.quant[1],na.rm = T)
lbound<-quantile(x = y, probs = outlier.quant[2],na.rm = T)
#sredi te autlajere bre
y[y>ubound]<-ubound
y[y<lbound]<-lbound
#forkastujem komplet vrednosti varijable shodno dobijenim vrednostima fit funkcije
median.H<-tabela[eval(default.varijabla)==0,median(eval(varijabla),na.rm = T)]
median.D<-tabela[eval(default.varijabla)==1,median(eval(varijabla),na.rm = T)]
y[is.na(y) & tabela[,eval(default.varijabla)]==1]<-median.D
y[is.na(y) & tabela[,eval(default.varijabla)]==0]<-median.H
p<-predict(loes_fit,y)
#p[p<0]=0.000001 #za svaki slucaj
# p[p>1]=0.999999
#trebaju mi log odds a ne pdjevi
tabela[,transformisana_varijabla:=log(p/(1-p))]
##########################################BOX COX transformacija#########################
# to find optimal lambda
vector<-tabela[,eval(varijabla)]
lambda = BoxCox.lambda( vector )
# now to transform vector
Box.cox.varijabla = BoxCox( vector, lambda)
tabela[,Box.cox.varijabla:=Box.cox.varijabla]
############################################################################################
# binovi #
############################################################################################
##############################log odds binovi#############################################
#racunam pdjeve za svaki bin i dodeljujem ih pored stare vrednosti varijable
#NA pretvaram u character da bih sracunao i za njega DF
tabela[,varijabla_Bin_numeric:=as.numeric(varijabla_Bin)][
,varijabla_Bin_numeric:=as.character(varijabla_Bin_numeric)][
is.na(varijabla_Bin_numeric),varijabla_Bin_numeric:="NA"]
tabela[,prob:=sum(eval(default.varijabla))/(.N),by = varijabla_Bin_numeric]
#record a plot
p1=ggplot(data=tabela, aes(varijabla_Bin_numeric))+geom_bar(aes(weight=eval(default.varijabla)))
#ali trebaju mi log odds naravno
tabela[,odds:=(prob/(1-prob))]
###################################woe binovi###############################################
data<-data.frame(
default.varijabla=tabela[,eval(default.varijabla)],
continualna_varijabla=tabela[,eval(varijabla)])
WOE = create_infotables(data = as.data.frame(data),
y="default.varijabla",
parallel=FALSE,
bins = broj_binova)
woe =WOE$Tables$continualna_varijabla[,c(1,4)]
#ako postoje missing values
if(woe[1,1]=="NA"){
woe$"varijabla_Bin_numeric"=c("NA",1:broj_binova)
} else {
woe$"varijabla_Bin_numeric"=as.character(1:broj_binova)
}
woe.plot<-plot_infotables(WOE,"continualna_varijabla")
#prebaci kategorije u brojeve pa njih u character zbog na iz prethodne tabele, pa na u character jos jednom da bi mogao da ga vlookapuje
tabela<-merge(x=tabela,y=woe, all.x = T)[order(id)][,id:=NULL]#varijabla_Bin_numeric je trazena varujabla
################################################################################################
# AUC vrednosti #
################################################################################################
#racunam auc vrednost, staru pa novu noooovu
#stara
auroc.s<-auc(
as.numeric(tabela[,eval(default.varijabla)]),
as.numeric(tabela[,eval(varijabla)]))
auc.vrednost.pre<-as.numeric(auroc.s)
#nova
auroc.n<-auc(
as.numeric(tabela[,eval(default.varijabla)]),
as.numeric(tabela[,transformisana_varijabla]))
auc.vrednost.posle<-as.numeric(auroc.n)
###############################################################################################
# Ostali Grafici #
###############################################################################################
col.num.default<-grep("default", colnames(tabela))
col.num.varijabla<-which(colnames(tabela)==varijabla)
ostali_plotovi_pre=ploting(tabela,col.num.varijabla,col.num.default)
col.num.default<-grep("default", colnames(tabela))
col.num.varijabla<-which(colnames(tabela)=="transformisana_varijabla")
ostali_plotovi_posle=ploting(tabela,col.num.varijabla,col.num.default)
col.num.varijabla<-which(colnames(tabela)=="Box.cox.varijabla")
box.cox_plotovi<-ploting(tabela, col.num.varijabla, col.num.default)
output<-list()
output = list(monotonicity_graph = p1,
ostali_plotovi_pre=ostali_plotovi_pre,
ostali_plotovi_posle=ostali_plotovi_posle,
woe.plot=woe.plot,
auc.vrednost=data.frame(auc.vrednost.pre,auc.vrednost.posle),
fit_funkcija_objekat = loes_fit)
tabela$transformisana_varijabla->output[[7]]
names(output)[7]<-paste(varijabla,".tr",sep = "")
tabela$odds->output[[8]]
names(output)[8]<-paste(varijabla,".odds",sep = "")
tabela$WOE->output[[9]]
names(output)[9]<-paste(varijabla,".WOE",sep = "")
Box.cox.varijabla->output[[10]]
names(output)[10]<-paste(varijabla,".Box.Cox",sep = "")
box.cox_plotovi->output[[11]]
names(output)[11]<-paste(varijabla,".Box.Cox.plot",sep = "")
output
}
Pokrice_neto_kamatar=calibrate_parameters(lrge.training, broj_binova=8,
"Pokrice_neto_kamata",
"default.y",
outlier.quant=c(0.95,0.05)
)
NaNs producedIgnoring unknown parameters: positionRemoved 124 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!Ignoring unknown parameters: positionRemoved 108 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!Ignoring unknown parameters: positionRemoved 124 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!
Pokrice_neto_kamatar$monotonicity_graph

Pokrice_neto_kamatar$ostali_plotovi_posle

Asset turnover
Asset_turnover=calibrate_parameters(lrge.training,"Asset_turnover","default.y")
Ignoring unknown parameters: positionRemoved 126 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!Ignoring unknown parameters: positionRemoved 110 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!Ignoring unknown parameters: positionRemoved 126 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!
Asset_turnover$ostali_plotovi_posle

Asset_turnover$monotonicity_graph

Kategoricke promenljive:
Postoje tri kategoricke varijable koje je potrebno analizirati:
- Sifra opstine-generalno veliki broj opstina ce praviti problem, preporuka je da se potencijalno izvrsi podela na Beograd i ostatak Srbije, ili, na velike gradove i male opstine, gde bi u velike gradove usli Beograd, Nis, Novi Sad, i na kraju cemo pokusati da upotrebimo ekonomsku razvijenost opstina kao pokazatelj. Ona se menja svake godine, ali kostur ostaje slican, pa bismo u ovom delu razvijanja modela uzeli vrednost iz 2014. godine, a ukoliko se ispostavi kao bitan faktor mozemo zatraziti seriju, koja, medjutim ne ide pre 2010. godine.
- Sifra sektora-generalno, ne postoji opste misljenje o ovoj varijabli, niti opravdanost zasto bi ona usla u obracun, stoji da je broj difolta po sektorima razlicit, ali neki sektori imaju vrlo mali broj observacija, tako da cemo morati pregrupisati varijable na najvece sektore i ostale, zavisno od vec navedenih kriterijuma u pocetku ovog poglavlja.
- Strani investitor-situacija je jasna
rpivotTable(lrge.training.kategoricke,
rows = "default.y",
cols = "Strani_investitor",
aggregatorName = "Count as Fraction of Columns")
Sifra sektora:
freq_table=function(dta,kategorical,default){
kategorical=as.name(kategorical)
default=as.name(default)
tmp=dta[,.N,by=.(eval(kategorical),eval(default))]
frekvenca_sektor<-dcast(tmp,eval(kategorical)~eval(default),value.var="N")
frekvenca_sektor$`0`[is.na(frekvenca_sektor$`0`)]=0
frekvenca_sektor$`1`[is.na(frekvenca_sektor$`1`)]=0
ukupno<-frekvenca_sektor$`0`+frekvenca_sektor$`1`
frekvenca_sektor<-cbind.data.frame(frekvenca_sektor,ukupno)
frekvenca_sektor[,default_rate:=frekvenca_sektor$`1`/ukupno]
as.data.frame(frekvenca_sektor)
}
freq_table(lrge.training.kategoricke,"Sifra_sektor","default.y")
Posmatrajuci tabelu vidimo da vec navedene kriterijume zadovoljavaju C, F, G sektor, tako da ostale mozemo svrstati u poseban sektor. Medjutim, ono sto uvidjamo je, nazalost, da sva tri sektora imaju slicnu stopu difolta kao i komplet uzorak, zakljucujemo da nam je ova varijabla beskorisna..osim F, gradjevinarstvo, koje mozemo tretirati kao pojedinacnu varijablu.
lrge.training.kategoricke$Sifra_sektor[lrge.training.kategoricke$Sifra_sektor!="F"]<-"Z"
lrge.test.kategoricke$Sifra_sektor[lrge.test.kategoricke$Sifra_sektor!="F"]<-"Z"
freq_table(lrge.training.kategoricke,"Sifra_sektor","default.y")
data_sifra_sektor<-lrge.training.kategoricke[,c("default.y","Sifra_sektor")]
IV_sifra_sektor<-create_infotables(data=data_sifra_sektor,
y="default.y",
parallel=FALSE)
IV_sifra_sektor$Tables
$Sifra_sektor
NA
Information value od 0.04 deluje kao prihvatljiv, ali ovde imamo samo 19 difoltera na jednu varijablu ciji bin ne ulazi
Sifra opstine:
U cilju iskorišćenja ove varijable posegnuli smo za podelom jedinica Lokalne samouprave po ekonomskoj razvijenosti, kao i na drugu podelu gde su Beograd, Novi SAd i Nis u jednoj kategoriji kao najveci gradovi, a ostali gradovi u ostalim kategorijama, na kraju mozemo i izdvojiti samo Beograd. Pregledajmo prvo kakvo je stanje po ostinama:
freq_table(lrge.training.kategoricke,"Sifra_opstine","default.y")
Uvidjamo da Beograd (najverovatnije) i Novi Sad jedini imaju preko 100 duznika, tako da ima smisla deliti na Beograd, Novi Sad i ostale opstine. Medjutim, vidimo da je default rate u Beogradu oko 10% sto je ,opet, blizu default ratea uzorka, samim tim, i Beograd otpada, ali bi eventualno mogli koristiti Novi Sad kao posebnu kategoriju. Pokusacemo da uvidimo da li nam predlozena varijabla o razvijenosti opstina donosi nesto novo (izvrsena je mala korekcija kod Zvecanj-a gde je dodata 4 kategorija ekonomske razvijenosti buduci da je opstina sa Kosova):
#ucitavam pripremljenu tabelu sa kategorijama razvijenosti
opstine_razvijenost <- read_delim("C:/Users/milos.cipovic/Desktop/Projekti/Early warning/Razvojni folder/Bottom Up/Korak 5/opstine_razvijenost.csv",
";", escape_double = FALSE, trim_ws = TRUE)
Parsed with column specification:
cols(
Total = col_integer(),
Razvijenost = col_character(),
Sifra_opstine = col_integer()
)
#opstine_razvijenost$Sifra_opstine<-factor(opstine_razvijenost$Sifra_opstine)
#jbg moramo voditi racuna o redosledu ovde!!!!!!
lrge.training.kategoricke$id <- 1:nrow(lrge.training.kategoricke)
lrge.test.kategoricke$id <- 1:nrow(lrge.test.kategoricke)
lrge.training.kategoricke<-merge(lrge.training.kategoricke,opstine_razvijenost,all.x = T)
lrge.test.kategoricke<-merge(lrge.test.kategoricke,opstine_razvijenost,all.x = T)
lrge.training.kategoricke<-lrge.training.kategoricke[order(lrge.training.kategoricke$id), ][,id:=NULL]
lrge.test.kategoricke<-lrge.test.kategoricke[order(lrge.test.kategoricke$id), ][,id:=NULL]
freq_table(lrge.training.kategoricke,"Razvijenost","default.y")
Ima logike svrstati cetvrtu i trecu kolonu u jednu, mada time podizemo default rate na 16% sa 12%, treba imati u obzir da je u ovu kolonu uslo i preduzece koje je sa Kosova koje je ranije bilo svrstano u ovu kategoriju, a koje je difoltiralo. Time bi broj observacija u klasi 3 bio \(99\approx100\). Koriscenje WOE i IV u slucaju velikih preduzeca, generalno, nije izvodljivo, usled malog broja difoltera po klasi faktorske varijable ( predlaze bar 50 difoltera po kategoriji klasifikacije), ipak pogledacemo ova dva statistika kao putokaz i imati u vidu predlog gde navodi za IV statistik sledece:
- Ukoliko je manji od 0.02, nije nam od preke vaznosti
- Ukoliko je izmedju 0.02 i 0.1 onda postoji slaba diskriminacija i veza sa racijom sansi
- Ukoliko je izmedju 0.1 i 0.3 onda postoji srednje jaka veya sa racijom sansi i
- Preko 0.3 oynacava sjajnu poveyanost sa diskriminacijom i racijom sansi (Srpski za Good/Bad odds ratio)
Spojili smo 4 i 3 kategoriju
#kreiram novu varijablu gde 4 pripajam 3jci
lrge.training.kategoricke$Razvijenost[lrge.training.kategoricke$Razvijenost==4]<-3
lrge.test.kategoricke$Razvijenost[lrge.test.kategoricke$Razvijenost==4]<-3
freq_table(lrge.training.kategoricke,"Razvijenost","default.y")
data_opstine_po_razvijenosti<-lrge.training.kategoricke[,c("default.y","Razvijenost")]
IV_opstine_po_razvijenosti<-create_infotables(data=data_opstine_po_razvijenosti,
y="default.y",
parallel=FALSE)
IV_opstine_po_razvijenosti$Tables
$Razvijenost
NA
Dobili smo IV oko 0.07 sto zadovoljava medjutim jako je mali broj difolta u kategoriji 3 imajuci u vidu broj opstina koje spadaju u nju, spajamo 2 i 3
#kreiram novu varijablu gde 3 i 2 spajam
lrge.training.kategoricke$Razvijenost[lrge.training.kategoricke$Razvijenost==3]<-2
lrge.test.kategoricke$Razvijenost[lrge.test.kategoricke$Razvijenost==3]<-2
freq_table(lrge.training.kategoricke,"Razvijenost","default.y")
data_opstine_po_razvijenosti<-lrge.training.kategoricke[,c("default.y","Razvijenost")]
IV_opstine_po_razvijenosti<-create_infotables(data=data_opstine_po_razvijenosti,
y="default.y",
parallel=FALSE)
IV_opstine_po_razvijenosti$Summary
Oko 0.04 sto bi moglo da nam znaci nesto
Pokusajmo sada sa Novim Sadom:
lrge.training.kategoricke$Sifra_opstine[lrge.training.kategoricke$Sifra_opstine!="89010"]<-"0000"
lrge.test.kategoricke$Sifra_opstine[lrge.test.kategoricke$Sifra_opstine!="89010"]<-"0000"
freq_table(lrge.training.kategoricke,"Sifra_opstine","default.y")
data_2opstine<-lrge.training.kategoricke[,c("default.y","Sifra_opstine")]
IV_2opstine<-create_infotables(data=data_2opstine,
y="default.y",
parallel=FALSE)
IV_2opstine$Summary
Ipak cemo ici sa opstinama po razvijenosti
Strani investitor
Pogledajmo prvo frekvencionu tabelu
freq_table(lrge.training.kategoricke,"Strani_investitor","default.y")
Postoji ocigledna razlika, imajuci u vidu da ovde imamo samo dve varijable, to je i ocekivano, hajde da vidimo IV:
IV_strani_investitor$Tables
$Strani_investitor
NA
Imamo IV oko 0.03. Uzecemo ovako.
Evaluacija regresije
Dosadasnji rezultati:
Otpadanje usled NA vrednosti, prezivele su sledece varijable:
summary_table<-as.data.frame(summary_table)
preziveli.NA<-rownames(summary_table[summary_table$NAspercent<10,])
knitr::kable(preziveli.NA)
The table should have a header (column names)
| Broj_zaposlenih |
| Velicina |
| Rigorozni_racio_redukovane_(monetarne)_likvidnosti |
| Racio_novcane_likvidnosti_(Cash_ratio) |
| Opsti_racio_likvidnosti |
| Stepen_zaduzenosti |
| Racio_pokrica_kamata_zaradom_pre_kamata_i_poreza_(Interest_Coverage_Ratio) |
| Racio_pokrica_obrtne_imovine |
| Gotovinski_ciklus_1 |
| Vreme_vezivanja_zaliha |
| Vreme_kreditiranja_kupaca |
| Vreme_naplate_potrazivanja |
| Vreme_placanja_dobavljacima |
| Asset_turnover |
| Stopa_prinosa_na_sopstveni_kapital_pre_oporezivanja |
| Stopa_prinosa_na_ukupna_sredstva_pre_oporezivanja |
| Basic_Earnings_Power_Ratio |
| Pokrice_neto_kamata |
| Cena_tudjih_izvora_sredstava |
| T11 |
| T12 |
| T13 |
| T14 |
| T15 |
| T21 |
| Altman I |
| Altman emerging markets |
| Altman private firms |
| udeo_u_kapitalu |
Ciscenje usled korelacija i AUROC-a manjeg od 0.55
preziveli.corr.AUC<-row.names(clean_cor)
Presek ova dva nastavlja u multivariate.
#odabrani<-c("Racio_novcane_likvidnosti_(Cash_ratio)",intersect(preziveli.NA,preziveli.corr.AUC))
odabrani<-intersect(preziveli.NA,preziveli.corr.AUC)
Ovde podsecamo da cemo ipak dodati kash racio u grupu. Nismo proveravali ovde redove ali bi trebalo kada budemo radila sa malim i srednjim preduzecima. Sredimo sada NA vrednosti:
Funkcija za nedostajuce i ekstreme:
replace_outlier_with_quantile <-
function(x,
quant = TRUE,
probs = c(0.01, 0.99),
na.rm = TRUE) {
if (quant == T) {
qnt <- quantile(x, probs = probs, na.rm = na.rm) # get %iles
U <- qnt[2]
L <- qnt[1]
y <- x
y[x < L] <- L # replace values below lower bounds
y[x > U] <- U
y
} else if (quant == F) {
qnt <- quantile(x, probs = c(.25, .75), na.rm = na.rm) # get %iles
H <- 3 * IQR(x, na.rm = na.rm) # outlier limit threshold
y <- x
y[x < (qnt[1] - H)] <-
(qnt[1] - H) # replace values below lower bounds
y[x > (qnt[2] + H)] <-
(qnt[2] + H) # replace values above higher bound
y # returns treated variable
}
}
replace_missing_with_median <-
function(x,
default.colona = as.name(default.y),
probs = c(0.01, 0.99),
na.rm = TRUE,
training = T,
...) {
x < as.data.frame(x)
median. <-
median(x, na.rm = na.rm)
median.h = median(x[default.colona == 0], na.rm = na.rm)
median.d = median(x[default.colona == 1], na.rm = na.rm)
if (training == T) {
x[is.na(x) & default.colona == 0] <- median.h
x[is.na(x) &
default.colona == 1] <-
median.d
} else {
x[is.na(x)] <- median.
}
x
}
replace_outlier_with_na <- function(x,quant = TRUE,
probs = c(0.01, 0.99),
na.rm = TRUE) {
if (quant == T) {
qnt <- quantile(x, probs = probs, na.rm = na.rm) # get %iles
U <- qnt[2]
L <- qnt[1]
y <- x
y[x < L] <- NA # replace values below lower bounds
y[x > U] <- NA
y
} else if (quant == F) {
qnt <- quantile(x, probs = c(.25, .75), na.rm = na.rm) # get %iles
H <- 3 * IQR(x, na.rm = na.rm) # outlier limit threshold
y <- NA
y[x < (qnt[1] - H)] <- NA # replace values below lower bounds
y[x > (qnt[2] + H)] <- NA # replace values above higher bound
y # returns treated variable
}
}
replace_missing_with_knn <- function(x, response_name = "default.y", training = T) {
x <- as.data.frame(x)
response<-x[,eval(response_name)]
if (training == F) {
if (anyNA(x)) {
x[,!names(x) %in% response_name] <-
knnImputation(x[,!names(x) %in% response_name]) # missing value treatment
}
} else {
if(anyNA(x)) {
x[response==1,!names(x) %in% response_name] <-
knnImputation(x[response==1,!names(x) %in% response_name]) # missing treatment
}
if (anyNA(x)) {
x[response==0,!names(x) %in% response_name] <-
knnImputation(x[response==0,!names(x) %in% response_name]) # missing value treatment
}
}
as.data.table(x)
}
#inputData_cont <- as.data.frame (sapply(clean_b[,9:34], replace_outlier_with_missing)) # this will make outliers as NA
#summary_table2<-sapply(inputData_cont,my.summary,arg=T)
Kreiramo zavrsni uzorak:
______________________
Tretman nedostajucih i tretman autlajera, potom dodajemo kategoricke
finalni_lrge<-lrge.training[,c(odabrani), with=F]
#finalni_lrge<-cbind.data.frame(finalni_lrge,Asset_turnover$Asset_turnover.tr,Pokrice_neto_kamata$Pokrice_neto_kamata.tr)
#finalni_lrge<-as.data.table(sapply(finalni_lrge,replace_outlier_with_quantile))
finalni_lrge<-as.data.table(sapply(finalni_lrge,replace_outlier_with_na))
finalni_lrge$default.y<-lrge.training$default.y
finalni_lrge<-replace_missing_with_knn(finalni_lrge)
finalni_lrge$default.y<-NULL
############################################################################
# opciono #
# #
############################################################################
AA<-data.frame(1:1255);n=1 #
finalni_lrge$default.y <- default.y #
for(i in names(finalni_lrge)["default.y" != names(finalni_lrge)]) {
n = n + 1
tmp <- calibrate_parameters(finalni_lrge, i, "default.y")
AA <- cbind.data.frame(AA, tmp[[7]])
names(AA)[n] <- names(finalni_lrge)[n]
}
finalni_lrge <- AA
remove(AA)
finalni_lrge[, 1] <- NULL
#
#
finalni_lrge$default.y <- default.y #
finalni_lrge <- as.data.table(finalni_lrge) #
###########################################################################
#spajamo sa kategorickim i skidamo par viskova kategorickih, velicina, total
finalni_lrge <-
cbind.data.frame(finalni_lrge, lrge.training.kategoricke)[, c("Velicina", "Total", "Sifra_sektor","Sifra_opstine") :=
NULL]
#pretvaram kategoricke u faktor da bi ih glm posmatrao kao kategoricke
finalni_lrge$Razvijenost <- as.factor(finalni_lrge$Razvijenost)
finalni_lrge$Strani_investitor <-
as.factor(finalni_lrge$Strani_investitor)
Dugo ocekivani trenutak:
model.null = glm(default.y ~ 1,
data=finalni_lrge,
family = binomial(link="logit")
)
model.full = glm(default.y ~ .,
data=finalni_lrge,
family = binomial(link="logit")
)
step(model.null,
scope = list(upper=model.full,lower=model.null),
direction="forward",
data=finalni_lrge,trace=0)
Call: glm(formula = default.y ~ Stopa_prinosa_na_ukupna_sredstva_pre_oporezivanja +
`Racio_novcane_likvidnosti_(Cash_ratio)` + Stepen_zaduzenosti +
Gotovinski_ciklus_1 + Cena_tudjih_izvora_sredstava + Razvijenost +
T21 + Racio_pokrica_obrtne_imovine, family = binomial(link = "logit"),
data = finalni_lrge)
Coefficients:
(Intercept)
-4.810710
Stopa_prinosa_na_ukupna_sredstva_pre_oporezivanja
-0.042006
`Racio_novcane_likvidnosti_(Cash_ratio)`
-4.216509
Stepen_zaduzenosti
0.031723
Gotovinski_ciklus_1
-0.001379
Cena_tudjih_izvora_sredstava
0.023292
Razvijenost2
0.289870
Razvijenost3
0.977524
T21
1.389687
Racio_pokrica_obrtne_imovine
-0.091868
Degrees of Freedom: 1254 Total (i.e. Null); 1245 Residual
Null Deviance: 818.2
Residual Deviance: 719.4 AIC: 739.4
model1 <- glm(formula =default.y~`Racio_novcane_likvidnosti_(Cash_ratio)`+Stepen_zaduzenosti+Gotovinski_ciklus_1+Vreme_naplate_potrazivanja+Stopa_prinosa_na_sopstveni_kapital_pre_oporezivanja+Cena_tudjih_izvora_sredstava, family = binomial(link = "logit"),
data = finalni_lrge)
model1.data.frame<-data.frame(fit1=model1$fitted.values, dif1=model1$model$default.y)
step(model.full,
scope = list(lower=model.full,upper=model.null),
direction="backward",
data=finalni_lrge, trace=0)
Call: glm(formula = default.y ~ `Rigorozni_racio_redukovane_(monetarne)_likvidnosti` +
`Racio_novcane_likvidnosti_(Cash_ratio)` + Stepen_zaduzenosti +
`Racio_pokrica_kamata_zaradom_pre_kamata_i_poreza_(Interest_Coverage_Ratio)` +
Racio_pokrica_obrtne_imovine + Gotovinski_ciklus_1 + Vreme_kreditiranja_kupaca +
Vreme_naplate_potrazivanja + Vreme_placanja_dobavljacima +
Stopa_prinosa_na_sopstveni_kapital_pre_oporezivanja + Stopa_prinosa_na_ukupna_sredstva_pre_oporezivanja +
Cena_tudjih_izvora_sredstava + T14 + T21 + udeo_u_kapitalu +
Strani_investitor + Razvijenost, family = binomial(link = "logit"),
data = finalni_lrge)
Coefficients:
(Intercept)
-4.668e+00
`Rigorozni_racio_redukovane_(monetarne)_likvidnosti`
-2.929e-02
`Racio_novcane_likvidnosti_(Cash_ratio)`
-3.963e+00
Stepen_zaduzenosti
3.233e-02
`Racio_pokrica_kamata_zaradom_pre_kamata_i_poreza_(Interest_Coverage_Ratio)`
-8.045e-07
Racio_pokrica_obrtne_imovine
-8.617e-02
Gotovinski_ciklus_1
-1.470e-03
Vreme_kreditiranja_kupaca
-1.278e-03
Vreme_naplate_potrazivanja
1.274e-03
Vreme_placanja_dobavljacima
-1.462e-04
Stopa_prinosa_na_sopstveni_kapital_pre_oporezivanja
-3.180e-04
Stopa_prinosa_na_ukupna_sredstva_pre_oporezivanja
-4.009e-02
Cena_tudjih_izvora_sredstava
2.248e-02
T14
6.987e-04
T21
1.333e+00
udeo_u_kapitalu
2.525e-04
Strani_investitor1
-1.159e-01
Razvijenost2
3.003e-01
Razvijenost3
9.554e-01
Degrees of Freedom: 1254 Total (i.e. Null); 1236 Residual
Null Deviance: 818.2
Residual Deviance: 717.2 AIC: 755.2
model2<- glm(formula = default.y ~ `Rigorozni_racio_redukovane_(monetarne)_likvidnosti` +
`Racio_novcane_likvidnosti_(Cash_ratio)` + Stepen_zaduzenosti +
`Racio_pokrica_kamata_zaradom_pre_kamata_i_poreza_(Interest_Coverage_Ratio)` +
Racio_pokrica_obrtne_imovine + Gotovinski_ciklus_1 + Vreme_kreditiranja_kupaca +
Vreme_naplate_potrazivanja + Vreme_placanja_dobavljacima +
Stopa_prinosa_na_sopstveni_kapital_pre_oporezivanja + Stopa_prinosa_na_ukupna_sredstva_pre_oporezivanja +
Cena_tudjih_izvora_sredstava + T14 + T21 + udeo_u_kapitalu +
Strani_investitor + Razvijenost, family = binomial(link = "logit"),
data = finalni_lrge)
model2.data.frame=data.frame(fit2=model2$fitted.values, dif2=model2$model$default.y)
Wald statistik:
library(car)
package 㤼㸱car㤼㸲 was built under R version 3.3.3
Attaching package: 㤼㸱car㤼㸲
The following object is masked from 㤼㸱package:gtools㤼㸲:
logit
Anova(model1, type="II", test="Wald")
Analysis of Deviance Table (Type II tests)
Response: default.y
Df Chisq Pr(>Chisq)
Stopa_prinosa_na_ukupna_sredstva_pre_oporezivanja 1 12.7734 0.0003516 ***
`Racio_novcane_likvidnosti_(Cash_ratio)` 1 9.0301 0.0026556 **
Stepen_zaduzenosti 1 8.3352 0.0038883 **
Gotovinski_ciklus_1 1 3.8995 0.0483006 *
Cena_tudjih_izvora_sredstava 1 8.6873 0.0032043 **
Razvijenost 2 10.4438 0.0053972 **
T21 1 6.2816 0.0121997 *
Racio_pokrica_obrtne_imovine 1 2.6143 0.1059071
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Langrange multiplier test:
anova(model2,
model.null,
test="Chisq")
Analysis of Deviance Table
Model 1: default.y ~ `Rigorozni_racio_redukovane_(monetarne)_likvidnosti` +
`Racio_novcane_likvidnosti_(Cash_ratio)` + Stepen_zaduzenosti +
`Racio_pokrica_kamata_zaradom_pre_kamata_i_poreza_(Interest_Coverage_Ratio)` +
Racio_pokrica_obrtne_imovine + Gotovinski_ciklus_1 + Vreme_kreditiranja_kupaca +
Vreme_naplate_potrazivanja + Vreme_placanja_dobavljacima +
Stopa_prinosa_na_sopstveni_kapital_pre_oporezivanja + Stopa_prinosa_na_ukupna_sredstva_pre_oporezivanja +
Cena_tudjih_izvora_sredstava + T14 + T21 + udeo_u_kapitalu +
Strani_investitor + Razvijenost
Model 2: default.y ~ 1
Resid. Df Resid. Dev Df Deviance Pr(>Chi)
1 1236 717.15
2 1254 818.15 -18 -101 1.452e-13 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Drugi nacin
auroc.1<-auc(
as.numeric(model1.data.frame$dif1),
as.numeric(model1.data.frame$fit1))
auroc.2<-auc(
as.numeric(model2.data.frame$dif2),
as.numeric(model2.data.frame$fit2))
c(auroc.1,auroc.2)
[1] 0.7600067 0.7684494
validacioni uzorak
106264 96946
finalni_lrge.test<-lrge.test[,c(odabrani), with=F]
#finalni_lrge<-cbind.data.frame(finalni_lrge,Asset_turnover$Asset_turnover.tr,Pokrice_neto_kamata$Pokrice_neto_kamata.tr)
finalni_lrge.test<-as.data.table(sapply(finalni_lrge.test,replace_outlier_with_na))
finalni_lrge.test$default.y<-lrge.test$default.y
finalni_lrge.test<-replace_missing_with_knn(finalni_lrge.test,training = F)
finalni_lrge.test$default.y<-NULL
finalni_lrge.test <-
cbind.data.frame(finalni_lrge.test, lrge.test.kategoricke)[, c("Velicina", "Total", "Sifra_sektor","Sifra_opstine") :=
NULL]
#pretvaram kategoricke u faktor da bi ih glm posmatrao kao kategoricke
finalni_lrge.test$Razvijenost <- as.factor(finalni_lrge.test$Razvijenost)
finalni_lrge.test$Strani_investitor <-
as.factor(finalni_lrge.test$Strani_investitor)
model1.pred<-as.numeric(predict(model1, newdata = finalni_lrge.test, type = "response"))
model2.pred<-as.numeric(predict(model2, newdata = finalni_lrge.test, type = "response"))
dif<-as.numeric(finalni_lrge.test$default.y)
auroc.1.pred<-auc( dif,model1.pred)
auroc.2.pred<-auc( dif,model2.pred)
c(auroc.1.pred,auroc.2.pred)
[1] 0.7541885 0.7445262
Konacno biramo ovu formulu:
glm(formula =default.y~Racio_novcane_likvidnosti_(Cash_ratio)+Stepen_zaduzenosti+Gotovinski_ciklus_1+Vreme_naplate_potrazivanja+Stopa_prinosa_na_sopstveni_kapital_pre_oporezivanja+Cena_tudjih_izvora_sredstava, family = binomial(link = “logit”), data = finalni_lrge)`
______________________________________
LS0tDQp0aXRsZTogIlNrdXBsamFuamUgcG9kYXRha2EgemEgRVctTkJTIg0Kb3V0cHV0Og0KICBodG1sX25vdGVib29rOiANCiAgICB0b2M6IHllcw0KICBodG1sX2RvY3VtZW50OiBkZWZhdWx0DQotLS0NCg0KPGJvZHkgc3R5bGU9ImZvbnQtZmFtaWx5OnRpbWVzO3RleHQtYWxpZ246anVzdGlmeSIgPg0KIyMgMS4gVWNpdGF2YW5qZSBwb2RhdGFrYSBBUFItYSAgDQoNClVjaXRhY2VtbyBkdmEgY3N2IGZhamxhLCBqZWRhbiBzYWRyemkgc3RhcmlqZSBkYXR1bWUgZG8gMjAxMy4gZ29kaW5lIGRvayBkcnVnaSBzYWRyemkgbm92aWplIGRhdHVtZSBvZCAyMDE0LiBnb2RpbmUgcGEgbmEgZGFsamUuIFV2ZXppdmFuamUgQU9QLWEgcG8gbm92b20gaSBzdGFyb20ga29udG5vbSBva3ZpcnUgamUgdmVjIHVyYWRqZW5vIGkgc2FjdXZhbm8gdSBkYXRhIGR2YSBjc3YgZmFqbGEuIFNhbWkgZmFqbG92aSBuZSBzYWRyemUgQU9QLWUhISEgUmF6bG9nIGplIMWhdG8gbmUgYmkgbW9nbGkgZGEgc2Ugc3BvamUgdSBqZWRhbiBmYWpsIGJ1ZHXEh2kgZGEgQU9QLWkgIHBvIHN0YXJvbSBpIG5vdm9tIGtvbnRub20gb2t2aXJ1IG5pc3UgbWFwaXJhbmkgamVkYW5hIG5hIGplZGFuIGkgc2FtaW0gdGltIG5lIGJpIG1vZ2xpIGRhIHNlICJuYWxlcGUiIGplZGFuIG5hIGRydWdpIHUgY2lsanUgZG9iaWphbmphIGplZG5vZyBgZGF0YS5mcmFtZWAtYSBqZXIgYmkgaW1hbGkgcmF6bGljaXQgYnJvaiBBT1AtYSAoY2l0YWoga29sb25hKSwgZmFqbG92aSBtZWRqdXRpbSBzYWRyemUgcHJvcmFjdW5hdGEgZmluYW5zaWpza2EgcmFjaWphLiBGYWpsb3ZpIHNhZHJ6ZSBmaW5hbnNpanNrYSByYWNpamEga29qYSBzdSBzcmFjdW5hdGEgaXogcHJlbWFwaXJhbmloIGl6IEFPUC1hIGR2YSBrb250bmEgb2t2aXJhIChub3ZpIGkgc3Rhcmkga29udG5pIG9rdmlyKS4gWmEgZGV0YWxqbmlqaSBwcmVnbGVkLCB1dmlkIHUgcG9qZWRpbmFjbmUgQU9QLWUgcG9nbGVkYXRpIGZhamxvdmUgaXogZm9sZGVyYSBvdmUgYW5hbGl6ZSwgZmFqbG92aSBjZSBzZSBuYWxheml0aSB1IDxmb250IGNvbG9yPSJyZWQiPiJ+XFxFYXJseSB3YXJuaW5nXFxCb3R0b20gVXBcXEtvcmFrIDNcXFBva2F6YXRlbGppIjwvZm9udD4gZ2RlICB+IHByZWRzdGF2bGphIGFkcmVzdSBuYSBrb2pvaiBqZSBwb3N0YXZsamVuIGZvbGRlci4gIA0KRG9kYXRubyBwb2phc25qZW5qZSBvIHRvbGlrbyBzcG9taW5qYW5pbSBBT1AtaW1hOg0KDQo8cCBzdHlsZT0ibWFyZ2luLWxlZnQ6IDQwcHg7bWFyZ2luLXJpZ2h0OiA0MHB4O3RleHQtYWxpZ246anVzdGlmeTtjb2xvcjpncmF5Ij4NClUgQVBSIGJhemkgc3Ugc3ZlIHBvemljaWplIGl6IGJpbGFuc2Egc3RhbmphLCBiaWxhbnNhIHVzcGVoYSwgdG9rb3ZhIGdvdG92aW5lLCBzdGF0aXN0aWNraWggcG9kYXRha2EgbyBwcmVkdXplY3UgKHN0YXRpc3RpY2tpIGFuZWtzKSB0cmV0aXJhbmUga2FvIEFPUCBwb3ppY2lqZSwgdGFrbyBuYSBwcmltZXIgYnJvaiB6YXBvc2xlbmloIGRhdG9nIHByZWR1emVjYSBtb3plbW8gbmFjaSB1IHBvbGp1IEFPUCA2MDUgemEgdGFqIG1hdGljbmkgYnJvaiwgaWxpIG5hIHByaW1lciB2cmVkbm9zdCBzdGFsbmUgaW1vdmluZSBpeiBiaWxhbnNhIHN0YW5qYSBzZSBuYWxhemkgdSBwb2xqdSBBT1AgMDAxLiBNZWRqdXRpbSB1c2xlZCBtZW5qYW5qYSBrb250bm9nIG9rdmlyYSBub3ZpIEFPUC1pIHNhZGEgaW1hanUgNCAgdW1lc3RvIDMgY2lmcmUgdGFrbyBkYSBnb3JlIG5hdmVkYW5lIGR2ZSB2YXJpamFibGUgc2Ugc2FkYSBuYWxhemUgcG9kIEFPUC1pbWEgOTAwNSBpIDAwMDIgcmVzcGVrdGl2bm8uIE1lZGp1dGltIG5lbW9ndWNlIGplIHByZW1hcGlyYXRpIHN2ZSBBT1AtZSBwbyBzdGFyb20gbmFjaW51IGl6dmVzdGF2YW5qYSBzYSBBT1AtaW1hIHBvIG5vdm9tIG5hY2ludSBpenZlc3RhdmFuamEgamVkYW4gbmEgamVkYW4gcGEgamUgc2FtaW0gdGltIGJpbG8gaSBuZW1vZ3VjZSBwcmlrYXphdGkgdGFiZWxhIHNhIHZhcmlqYWJsYW1hIGtvamUgdWNlc3R2dWp1IHUgcHJvcmFjdW51IGZpbmFuc2lqc2tpaCByYWNpamEsIHZlYyBzdSBzYW1vIHByaWthemFuaSBmaW5hbnNpanNraSByYWNpamkga2FvIGtyYWpuamkgcmV6dWx0YXQuDQo8L3A+DQoNCkNpbGogamUgc3Bvaml0aSBvdmEgZHZhIGNzdiBmYWpsYSB1IGplZGFuLiBVY2l0YW1vIGZpbmFuc2lqc2thIHJhY2lqYSBkbyAyMDEzLiBnb2RpbmU6DQpgYGB7cixldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQ0KI2dlbmVyYWxuZSBvcGNpamUgaSB1Y2l0YXZhbmplIHBvdHJlYm5paCBiaWJsaW90ZWthDQppZihyZXF1aXJlKCdyZWFkcicpPT1GKXtpbnN0YWxsLnBhY2thZ2VzKCdyZWFkcicpO3JlcXVpcmUoJ3JlYWRyJyl9DQppZihyZXF1aXJlKCJkYXRhLnRhYmxlIixxdWlldGx5ID0gRikgPT1GKXtpbnN0YWxsLnBhY2thZ2VzKCJkYXRhLnRhYmxlIik7cmVxdWlyZSgiZGF0YS50YWJsZSIscXVpZXRseSA9IEYpfQ0KaWYocmVxdWlyZSgnRFQnKT09Ril7aW5zdGFsbC5wYWNrYWdlcygnRFQnKTtyZXF1aXJlKCdEVCcpfQ0KaWYocmVxdWlyZSgnZTEwNzEnKT09Ril7aW5zdGFsbC5wYWNrYWdlcygnZTEwNzEnKTtyZXF1aXJlKCdlMTA3MScpfQ0KaWYocmVxdWlyZSgncnBpdm90VGFibGUnKT09Ril7aW5zdGFsbC5wYWNrYWdlcygncnBpdm90VGFibGUnKTtyZXF1aXJlKCdycGl2b3RUYWJsZScpfQ0KaWYocmVxdWlyZSgnY293cGxvdCcpPT1GKXtpbnN0YWxsLnBhY2thZ2VzKCdjb3dwbG90Jyk7cmVxdWlyZSgnY293cGxvdCcpfQ0KaWYocmVxdWlyZSgncGxvdFJPQycpPT1GKXtpbnN0YWxsLnBhY2thZ2VzKCdwbG90Uk9DJyk7cmVxdWlyZSgncGxvdFJPQycpfQ0KaWYocmVxdWlyZSgncFJPQycpPT1GKXtpbnN0YWxsLnBhY2thZ2VzKCdwUk9DJyk7cmVxdWlyZSgncFJPQycpfQ0KaWYocmVxdWlyZSgiSW5mb3JtYXRpb25WYWx1ZSIpPT1GKXtpbnN0YWxsLnBhY2thZ2VzKCJJbmZvcm1hdGlvblZhbHVlIik7cmVxdWlyZSgiSW5mb3JtYXRpb25WYWx1ZSIpfQ0KaWYocmVxdWlyZSgiSW5mb3JtYXRpb24iKT09Ril7aW5zdGFsbC5wYWNrYWdlcygiSW5mb3JtYXRpb24iKTtyZXF1aXJlKCJJbmZvcm1hdGlvbiIpfQ0KaWYocmVxdWlyZSgiZ3Rvb2xzIik9PUYpe2luc3RhbGwucGFja2FnZXMoImd0b29scyIpO3JlcXVpcmUoImd0b29scyIpfQ0KaWYocmVxdWlyZSgiZm9yZWNhc3QiKT09Ril7aW5zdGFsbC5wYWNrYWdlcygiZm9yZWNhc3QiKTtyZXF1aXJlKCJmb3JlY2FzdCIpfQ0KaWYocmVxdWlyZSgic3BlZWRnbG0iKT09Ril7aW5zdGFsbC5wYWNrYWdlcygic3BlZWRnbG0iKTtyZXF1aXJlKCJzcGVlZGdsbSIpfQ0KaWYocmVxdWlyZSgibWx0b29scyIpPT1GKXtpbnN0YWxsLnBhY2thZ2VzKCJtbHRvb2xzIik7cmVxdWlyZSgibWx0b29scyIpfQ0KaWYocmVxdWlyZSgiRE13UiIpPT1GKXtpbnN0YWxsLnBhY2thZ2VzKCJETXdSIik7cmVxdWlyZSgiRE13UiIpfQ0KDQpgYGAgIA0KDQpgYGB7cn0NClBva2F6YXRlbGppX3N0YXJpIDwtIHJlYWRfZGVsaW0oIkM6L1VzZXJzL21pbG9zLmNpcG92aWMvRGVza3RvcC9Qcm9qZWt0aS9FYXJseSB3YXJuaW5nL1JhenZvam5pIGZvbGRlci9Cb3R0b20gVXAvS29yYWsgMy9Qb2themF0ZWxqaS9Qb2themF0ZWxqaSBzdGFyaS5jc3YiLCI7IiwgZXNjYXBlX2RvdWJsZSA9IEZBTFNFLCBjb2xfdHlwZXMgPSBjb2xzKERhdHVtID0gY29sX2RhdGUoZm9ybWF0ID0gIiVtLSVkLSVZIikpLCBsb2NhbGUgPSBsb2NhbGUoZW5jb2RpbmcgPSAiQVNDSUkiKSwgdHJpbV93cyA9IFRSVUUsIHByb2dyZXNzID1GQUxTRSkNCmdjKCkNCmBgYA0KDQpVY2l0YW1vIGZpbmFuc2lqc2thIHJhY2lqYSBwb3NsZSAyMDEzLiBnb2RpbmUNCmBgYHtyLCBldmFsPUZBTFNFfQ0KUG9rYXphdGVsamlfbm92aSA8LQ0KICByZWFkX2RlbGltKA0KICAiQzovVXNlcnMvbWlsb3MuY2lwb3ZpYy9EZXNrdG9wL1Byb2pla3RpL0Vhcmx5IHdhcm5pbmcvUmF6dm9qbmkgZm9sZGVyL0JvdHRvbSBVcC9Lb3JhayAzL1Bva2F6YXRlbGppL1Bva2F6YXRlbGppIG5vdmkuY3N2IiwNCiAgIjsiLA0KICBlc2NhcGVfZG91YmxlID0gRkFMU0UsDQogIGNvbF90eXBlcyA9IGNvbHMoRGF0dW0gPSBjb2xfZGF0ZShmb3JtYXQgPSAiJW0tJWQtJVkiKSksDQogIGxvY2FsZSA9IGxvY2FsZShlbmNvZGluZyA9ICJBU0NJSSIpLA0KICB0cmltX3dzID0gVFJVRSwNCiAgcHJvZ3Jlc3MgPUYgDQogICkNCiAgZ2MoKQ0KYGBgDQoNClNwYWphbW8gdGFiZWxlIGBQb2themF0ZWxqaV9zdGFyaWAgaSBgUG9rYXphdGVsamlfbm92aWAgdSBqZWRudSB0YWJlbHUsIG92ZSBkdmUgdGFiZWxlIHN1IHVzdHZhcmkgcHJlZHN0YXZsamFsZSBwcm9yYWN1bmF0YSBmaW5hbnNpanNrYSByYWNpamEuICBUYWJlbGUgc3UgZG9iaWplbmUgcHJldGhvZG5vbSBhbmFsaXRpa29tIGkgb2JyYWRvbSBwb2RhdGFrYSB1IGV4Y2VsdSBqZXIgbmlqZSBiaWxvIG1vZ3VjZSBkcnVnYWNpamUuLiBQb2tyZcSHZW1vIGByZWFkX0tBNF9SS19kYXRhYCBmdW5rY2lqdSB6YSBwcmlwcmVtYW5qZSBLQTQgaSBSSyBpenZlc3RhamEuIEtyZWlyYW5qZSBgTkJTX2RhdGFgIGZ1bmtjaWplIGplIHZlYyByYW5pamUgb3Bpc2FubyB1IHNjcmlwdHUgPGZvbnQgY29sb3I9InJlZCI+J35cXEVhcmx5IHdhcm5pbmdcXEJvdHRvbSBVcFxcS29yYWsgNFxcRWFybHkgd2FybmluZ1xcbmJzX2RhdGFfcHJlcC5SJzwvZm9udD4ga29qaSBzYWRyemkgc3VzdGluc2tpIGlzdGkga29kIGtvamkgaSBmdW5rY2lqYSBgcmVhZF9LQTRfUktfZGF0YWAuDQpgYGB7cixtZXNzYWdlPUZBTFNFLHdhcm5pbmc9RkFMU0UsZXZhbD1GQUxTRX0NCkFQUl9kYXRhIDwtIHJiaW5kLmRhdGEuZnJhbWUoUG9rYXphdGVsamlfc3RhcmksIFBva2F6YXRlbGppX25vdmkpDQpybShQb2themF0ZWxqaV9zdGFyaSAsIFBva2F6YXRlbGppX25vdmkpDQpnYygpDQoNCg0Kc291cmNlKCJuYnNfZGF0YV9wcmVwX2Z1bmN0aW9uLlIiKQ0KS0E0X3VybCA9ICJDOi9Vc2Vycy9taWxvcy5jaXBvdmljL0Rlc2t0b3AvQmF6ZSBwb2RhdGFrYS9LNCBpIEFQUiBpIE5QTC9LQTRfcG9kYWNpLnR4dCINClJLX3VybCA9ICJDOi9Vc2Vycy9taWxvcy5jaXBvdmljL0Rlc2t0b3AvQmF6ZSBwb2RhdGFrYS9LNCBpIEFQUiBpIE5QTC9SS19ub3ZpLnR4dCINCk5CU19kYXRhIDwtIHJlYWRfS0E0X1JLX2RhdGEoS0E0X3VybCwgUktfdXJsLCBjb25zZXF1dGl2ZV9kaWZvbHQ9RikNCg0KYGBgDQoNClNwYWphbW8gQVBSIGkgTkJTIHBvZGF0a2UgaSBpemJhY3VqZW1vIGtvbG9udSBgTmF6aXZTZWt0b3JgIGplciBwcmF2aSBwcm9ibGVtZSBwcmkgZWtzcG9ydHUuIFBvc3Rvamkgc2lmcm92YW5hIHZlcnppamEgb3ZlIGtvbG9uZSB0YWtvIGRhIHNtbyB1IHJlZHUsIHByZXppdmVjZW1vIGJleiBuamUuIFRha28gZGEgc2FkYSBpbWFtbyBwb2NldG51IHRhYmVsdSBzYSBwb2RhY2ltYSBrb2plIHBvc2VkdWplIE5CUyBvIGR1em5pY2ltYSBrb2ppIHNlIG5hbGF6ZSB1IGJhemkgQVBSLWEuIE9kIHBvZGF0YWthIGtvamUgcG9zZWR1amUgTkJTIG5hanZlY2kgem5hY2FqIG5hbSBwcmVkc3RhdmxqYSBpbmRpa2F0b3IgKmRpZm9sdGEqIGtvamkgbmFtIGdvdm9yaSBkYSBsaSBjZSBwb3NtYXRyYW5pIGR1em5payBzYSBzcmFjdW5hdGltIGZpbmFuc2lqc2tpbSByYWNpamltYSBpeiBBUFIgYmF6ZSBvdGljaSB1ICpkaWZvbHQqIHphIGR2ZSBnb2RpbmUgaWxpIG5lLg0KYGBge3IsIHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRX0NCmMgPSBtZXJnZSgNCiAgTkJTX2RhdGEsDQogIEFQUl9kYXRhLA0KICBieS54ID0gYygiTUFUX0JSX0RVWk5JS0EiLCAiREFUVU0ueCIpLA0KICBieS55ID0gYygiSm1iIiwgIkRhdHVtIikNCiAgKQ0KICAjcm0oQVBSX2RhdGEsTkJTX2RhdGEpDQogIGMgPSBhcy5kYXRhLnRhYmxlKGMpDQogIGNbLCBOYXppdlNla3RvciA6PSBOVUxMXQ0KYGBgDQpLYW8gcHJ2aSBrb3JhayB1IGRhbGpvaiBhbmFsaXppIHBvdHJlYm5vIGplIHByZSBzdmVnYSBvYnJhdGl0aSBwYXpuanUgbmEgbG9naWNub3N0IHVuZXNlbmloIHZyZWRub3N0aSBrYW8gaSBuYSBuZWRvc3RhanVjZSB2cmVkbm9zdGksIHRqLiBwcm9yYWN1bmF0aSBwcm9jZW5hdCBuZWRvc3RhanVjaWggdnJlZG5vc3RpLiBOZWxvZ2ljbm9zdGkgamUgbmFqbGFrc2UgcHJvdmVyaXRpIHByZWdsZWRvbSBzdW1hcm5paCBzdGF0aXN0aWthIHRha28gZGEgY2UgbmFtIHNsZWRlY2EgdGFiZWxhIHBvbW9jaSB1IHRvbWUuICANCg0KIyMgMi4gUHJlbGltaW5hcm5hIGFuYWxpemEgcG9kYXRha2ENCioqVGFiZWxhIDEuKiogcHJpa2F6dWplIGFyaXRtZXRpY2t1IHNyZWRpbnUsIHRyaW1vdmFudSB2cmVkbm9zdCBpc3RlLCB6YXRpbSBtZWRpamFudSwgc3RhbmRhcmRudSBkZXZpamFjaWp1LCB0cmVjaSBpIGNldHZydGkgc3RhdGlzdGlja2kgbW9tZW50LCBtaW5pbWFsbnUgaSBtYWtzaW1hbG51IHZyZWRub3N0IGthbyBpIHUgcG9zbGVkbmplbSByZWR1IHByb2NlbmF0IG5lZG9zdGFqdWNpaCB2cmVkbm9zdGkuIFUgdG9rdSBwcmlwcmVtZSBwb2RhdGFrYSB1IGV4Y2VsdSBwb2plZGluaSByYWNpamkgbmlzdSBtb2dsaSBiaXRpIHNyYWN1bmF0aSB1c2xlZCBuZWRvc3RhamFuamEgQU9QLWEgemEgZGF0dSBvcHNlcnZhY2lqdSwgcG9zbGVkaWNubyByYWNpbyBkYXRlIG9ic2VydmFjaWplIGNlIGltYXRpIHZyZWRub3N0IGlsaSBgI04vQWAgaWxpIGAjRElWLzAhYC4gT3ZlIGR2ZSB2cmVkbm9zdGkgY2VtbyB1IG5hc3Rhdmt1IHRyZXRpcmF0aSBrYW8gbmVkb3N0YWp1Y2UgamVyIG9uZSB0byB1IHN2b2pvaiBwcmlyb2RpIGkgamVzdS4gT3ZkZSBzbW8gaWggemFtZW5pbGkgbmVkb3N0YWp1Y2ltICpgTkFgKiB2cmVkbm9zdGltYSB1IFItdS4gDQoNCg0KDQpgYGB7cixtZXNzYWdlPUZBTFNFLHdhcm5pbmc9RkFMU0UsZXJyb3I9RkFMU0UsIGVycm9yPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KI3phbWVuanVqZW0gI0RJVi8wISBpICNOL0Egc2EgZGlmb2x0bm9tIHZyZWRub3N0aSB6YSBuZWRvc3RhanVjZSB2cmVkbm9zdGkgdSBSLXUNCmIgPC0gYw0KYiA8LSBhcy5kYXRhLmZyYW1lKGIpDQpmb3IgKGkgaW4gMjE6NTApIHsNCiAgdGVtcCA8LSBiWywgaV0NCiAgdGVtcFt0ZW1wID09ICIjTi9BIiB8IHRlbXAgPT0gIiNESVYvMCEiXSA8LSBOQQ0KICBiWywgaV0gPC0gdGVtcA0KICBiWywgaV0gPC0gYXMubnVtZXJpYyhiWywgaV0pDQp9DQoNCiNza2xhbmphbSBuZXBvdHJlYm5lIHRhYmVsZSBkYSBvc2xvYm9kaW0gbWVtb3JpanUgamVyIG1vcmEgc2UuLi5rYW8gaSBzdnVkYSBkbyBzYWRhDQpybSh0ZW1wLGksS0E0X3VybCxSS191cmwscmVhZF9LQTRfUktfZGF0YSxBUFJfZGF0YSkNCg0KI2tyZWlyYW0gZHVwbGlrYXQgdGFiZWxlIG5hIGtvbSBjdSBkYSBkYWxqZXJhZGltIGkgemFkcnphdmFtIHNhbW8gYml0bmUga29sb25lLA0KI3RqLiBuZWtlIGNlIG1pIGJpdGkgcG90cmVibmUga2FzbmlqZSBhbGkgemEgbmppaCBzYW0gc2lndXJhbiBkYSBzdSBvayBqZXIgc2FtIGloIGtyZWlyYW8gaSB2ZWMgcHJvdmVyaW8NCiN1IHByb2NlZHVyaSBrcmVpcmFuamEgcG9kYXRha2EgaXogYmFua2Fyc2tvZyBzZWt0b3JhDQpiIDwtIGRhdGEudGFibGUoYikNCmNsZWFuX2IgPC0gYlssIGMoMSwgNCwgMiwgOSwgNSwgNywgMTQsIDE2OjUwKV0NCg0KI2tyZWlyYW0gZnVua2NpanUgemEgcHJvcmFjdW4gc3VtbWFyeSBzdGF0aXN0aWthDQpteS5zdW1tYXJ5IDwtIGZ1bmN0aW9uKHgsIGFyZz1UKXsNCiAgeDwtYXMubWF0cml4KHgpDQogIG48LW5yb3coeCkNCiAgZGF0YS5mcmFtZShtZWFuPW1lYW4oeCwgbmEucm09YXJnKSwNCiAgICBUcmltbWVkX21lYW49bWVhbih4LHRyaW0gPSAwLjEsbmEucm09YXJnKSwNCiAgICBzZD1zZCh4LCBuYS5ybT1hcmcpLA0KICAgIG1lZGlhbj1tZWRpYW4oeCwgbmEucm09YXJnKSwNCiAgICBza2V3bmVzcz1lMTA3MTo6c2tld25lc3MoeCxuYS5ybT1hcmcpLA0KICAgIGt1cnRvc2lzPWUxMDcxOjprdXJ0b3Npcyh4LG5hLnJtPWFyZyksDQogICAgbWluPW1pbih4LCBuYS5ybT1hcmcpLA0KICAgIG1heD1tYXgoeCxuYS5ybT1hcmcpLCANCiAgICBGaXJzdF9xdWFydGlsZT1xdWFudGlsZSh4LDAuMjUsbmEucm09YXJnKSwNCiAgICBUaGlyZF9xdWFydGlsZT1xdWFudGlsZSh4LDAuNzUsbmEucm09YXJnKSwNCiAgICBuPWxlbmd0aCh4KSwNCiAgICBOQXNwZXJjZW50PXJvdW5kKHN1bShhcy5udW1lcmljKGlzLm5hKHgpKS9uKSoxMDAsMSkNCiAgICApDQp9DQoNCiNrcmVpcmFtIHN1bWFybnUgdGFiZWx1DQpzdW1tYXJ5X3RhYmxlMSA8LSBzYXBwbHkoY2xlYW5fYlssIDExOjQyXSwgbXkuc3VtbWFyeSwgYXJnID0gVCkNCg0KDQojcHJpbnR1amVtIGplIHUgbm90ZWJvb2sNCg0KdHJfc3VtbWFyeV90YWJsZTEgPC0gdChzdW1tYXJ5X3RhYmxlMSkNCmZvcm1hdFJvdW5kKA0KICBkYXRhdGFibGUodHJfc3VtbWFyeV90YWJsZTEsIGNhcHRpb24gPSAiVGFiZWxhIDEuOlN1bWFybmkgcHJpa2F6IiwNCiAgICAgICAgICAgIGZpbHRlciA9ICdub25lJyksDQogIGNvbHVtbnMgPSBjb2xuYW1lcyh0cl9zdW1tYXJ5X3RhYmxlMSkNCikNCg0KYGBgDQoNCg0KDQojIyMgMi4xIE5lbG9naWNuaSB1bm9zaSAgDQpVIG92b20ga29yYWt1IGplIHBvdHJlYm5vIHByZSBzdmVnYSBwcmVnbGVkYXRpIGthdGVnb3JpY2tlIHZhcmlqYWJsZSB6YSBuZWxvZ2ljbmUgdW5vc2UsIG5haW1lLCBwcmltZWNlbm8gamUgZGEgdmFyaWphYmxhIGtvamEgYmkgdHJlYmFsbyBkYSBvem5hY2F2YSB2ZWxpY2ludSBkdXpuaWthIGkgdXppbWEgdnJlZG5vc3RpIG9kIDEgZG8gNCBzYWRyemkgdnJlZG5vc3RpIGtvamUgc3Ugem5hY2Fqbm8gdmVjZVteMV0sIHRha29kamUsIG1hbG8gamUgdmVyb3ZhdG5vIGRhIGplIHByb3NlY2FuIGJyb2ogemFwb3NsZW5paCBpem5vc2kgYHIgcm91bmQoYXMubnVtZXJpYyh0cl9zdW1tYXJ5X3RhYmxlMVsxLDFdKSlgLiBVdmlkb20gdSBwb2RhdGtlIGRvc2xvIHNlIGRvIHpha2xqdWNrYSBkYSBzdSBkYXRlIG5lbG9naWNub3N0aSByZXp1bHRhdCByYXpsaWtlIHUgc3RydWt0dXJpIGl6dmVzdGFqYSBmaW5hbnNpanNraWggaW5zdGl0dWNpamEgaSBvc3RhbGloIGxpY2Ega29qYSBzdSBkdXpuYSBkYSBwb2RhdGtlIHVub3NlIHUgQVBSIGJhenUsIHRha28gZGEgQU9QIDYwMiBrb2QgZmluYW5zaWpza2loIGluc3RpdHVjaWphIG5lIHByZWRzdGF2bGphIHNpZnJ1IHZlbGljaW5lLCBpc3RvIHZhemkgaSB6YSBwb2xqZSBrb2plIG96bmFjYXZhIHNpZnJ1IGJyb2phIHphcG9zbGVuaWguIERhbGppbSB1dmlkb20gZG9sYXppIHNlIGRvIGpvcyBuZWtpaCBzYXpuYW5qYSB1IGtvbnppc3RlbnRub3N0aSBBT1AtYSA2MDIga29qaSBvem5hY2F2YSB2ZWxpY2ludSBsaWNhLCBuYWltZSwgb3Rrcml2ZW5vIGplIGpvcyBqZWRubyBwb2xqZSB1IGJhemkga29qdSBOQlMgcG9zZWR1amUsIGEga29qZSBub3NpIGluZm9ybWFjaWplIG8gdmVsaWNpbmkgbGljYSwgb3ZvIHBvbGplIG5lbWEgc2lmcnUgQU9QLWEuIFBvc2xlIHByb3ZlcmUgcG9kYXRha2Ega29qZSBwb3NlZHVqZW1vIGkgbmppaG92aW0gdXBvcmVkaml2YW5qZW0gc2EgdnJlZG5vc3RpbWEgc2EgQVBSIHNhanRhIG9wcmVkZWxpbGkgc21vIHNlIHphIEFPUCA2MDIuIFByZXRob2RubyBvcGlzYW5hIGR2YSBwb2xqYSBzdSBzZSB1IHBvamVkaW5pbSBzbHVjYWpldmltYSByYXpsaWtvdmFsYSwgemJvZyB0b2dhIGplIGkgaXp2cnNlbmEgYW5hbGl6YS4gTmFpbWUsIHBvbWVudXRvIHBvbGplIGtvamUgc2UgbmFsYXppIHUgcGl2b3QgdGFiZWxhbWEgKG5hY2luIG5hIGtvamkgTkJTIGltYSBwcmlzdHVwIEFQUiBiYXppKSBqZSB1IG9kcmVkamVub20gYnJvanUgc2x1Y2FqZXZhIHByaWtheml2YWxvIHBvZGF0a2Ugb2QgcHJldGhvZG5lIGdvZGluZS4gT3ZvIGplIHNsdWNhaiBzYW1vIHNhIHN0YXJpbSBuYWNpbm9tIGl6dmVzdGF2YW5qYSwgZGFrbGUgZG8gMjAxMy4gZ29kaW5lISAgDQpOYXN0YXZsamFtbyBzYSBhbmFsaXpvbSB0YWtvIHN0byBjZW1vIGl6YmFjaXRpIGl6IHRhYmVsZSBvYnNlcnZhY2lqZSBzYSB2cmVkbm9zdGltYSB1IGtvbG9uaSBgVmVsaWNpbmFgIHZlY2ltIG9kIDQgaSBtYW5qaW0gb2QgMSBpIHBvbm92byBwcmVnbGVkYXRpIHN0cnVrdHVydSBzdW1hcm5lIHRhYmVsZS4gTmFrbmFkbm8sIGl6YmFjaWNlbW8gc3ZhIGxpY2Ega29qYSBuZSBwcmlwYWRhanUgZ3J1cGkgPGZvbnQgY29sb3I9cmVkPiJQcml2cmVkbmloIGRydXN0YXZhIGkgemFkcnVnYSI8L2ZvbnQ+IG9iemlyb20gZGEgbmFydXNhdmFqdSBob21vZ2Vub3N0IHV6b3JrYSBrYW8gaSBkYSBpbSBBT1AgcG96aWNpamUgbmlzdSBtYXBpcmFuZSBrYW8gUHJpdnJlZG5pbSBkcnVzdGF2aW1hIGkgemFkcnVnYW1hIHBhIHN1IHNhbWltIHRpbSB0ZSBvYnNlcnZhY2lqZSBpIGdsYXZuaSB1enJvayBuZWtvbnppc3RlbnRub3N0aSB1IHBvZGFjaW1hLiAgIA0KDQpVdmlkb20gdSAqKlRhYmVsdSAyLioqIGkgcG9samEgYFZlbGljaW5hYCBpIGBCcm9qIHphcG9zbGVuaWhgIHZpZGltbyBkYSBzdSBzcmVkbmphIHZyZWRub3N0LCBtaW5pbXVtIGkgbWFrc2ltdW0gdSBwcmlodmF0bGppdmltIGdyYW5pY2FtYS4gUG9zbWF0cmFuamUgb3N0YWxpaCB2YXJpamFibGkgYmkgemFodGV2YWxvIGRldGFsam5panUgYW5hbGl6dSBzdmFrZSBvZCBuamloIHBvbmFvc29iLiBPdmFqIGtvcmFrIGNlIGJpdGkgdXJhZGplbiBrYXNuaWplIHUgKnVuaXZhcmlhdGUqIGFuYWxpemkgdGFrbyBkYSBjZSBzYWRhIGJpdGkgcHJlc2tvY2VuLiANCg0KYGBge3IsICwgd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFfQ0KI3VjaXRhdmFtIHVuYXByZWQgcHJpcHJlbWxqZW51IHRhYmVsdSBrb2phIG5hbSB6YSBwb3NtYXRyYW5pIG1iIGkgZ29kaW51IGRhamUgbmplZ292dSBwcmlwYWRub3N0IG9kcmVkamVub20gc2VrdG9ydSwgdGouIGdvdm9yaSBuYW0gaXoga29qZWcgamUgZmluYW5zaWpza29nIGl6dmVzdGFqYSBkYXRhIG9ic2VydmFjaWphIHUgQVBSLXUNCmdjKCkNCg0KUHJhdm5hX2Zvcm1hIDwtDQogIHJlYWRfZGVsaW0oDQogICJDOi9Vc2Vycy9taWxvcy5jaXBvdmljL0Rlc2t0b3AvUHJvamVrdGkvRWFybHkgd2FybmluZy9SYXp2b2puaSBmb2xkZXIvQm90dG9tIFVwL0tvcmFrIDUvUHJhdm5hIGZvcm1hLmNzdiIsDQogICJ8IiwNCiAgZXNjYXBlX2RvdWJsZSA9IEZBTFNFLA0KICB0cmltX3dzID0gVFJVRSwNCiAgY29sX3R5cGVzID0gY29scyhEYXR1bSA9IGNvbF9kYXRlKGZvcm1hdCA9ICIlWSIpKSwNCiAgcHJvZ3Jlc3MgPSBGQUxTRQ0KICApDQoNCiNtZXJkenVqZW0gcG9pZGF0a2Ugc2EgY2xlYW5fYiwgdGouIHByZWNpc2NhdmFtIGNsZWFuX2IgdGFrbyBzdG8gcG9zdG8gbWVyZHp1amVtIHphZHJ6aW0gc2FtbyBvbmUgc2EgDQojc2Egc2lmcm9tIDE0MDAwIHN0byBwcmVkc3RhdmxqYSAiUHJpdnJlZG5hIGRydXN0YXZhIGkgemFkcnVnZSINCmNsZWFuX2IgPC0NCiAgbWVyZ2UoDQogIGNsZWFuX2IsDQogIFByYXZuYV9mb3JtYSwNCiAgYnkueCA9IGMoIkRBVFVNLngiLCAiTUFUX0JSX0RVWk5JS0EiKSwNCiAgYnkueSA9IGMoIkRhdHVtMSIsICJKbWIiKQ0KICApDQoNCg0KDQpjbGVhbl9iIDwtDQogIGNsZWFuX2JbU2lmcmEgPT0gMTQwMF1bLCBjKCJOYXppdiIsICJTaWZyYSIsICJOYXppdlByYXZub2dMaWNhIikgOj0gTlVMTF0NCiAgI2l6YmFjaW0gdnJlZG5vc3RpIHZlbGljaW5hIGtvamUgc3UgdmVjZSBvZCA0LCBkb3VibGUgY2hlY2sgaW5hY2UgbmUgYmkgc21lbG8gZGEgc21hbmppIGJyb2ogcmVkb3ZhDQpjbGVhbl9iIDwtIGNsZWFuX2JbVmVsaWNpbmEgPD0gNCAmIFZlbGljaW5hID4gMF0NCiNwb25vdm8ga3JlaXJhbSBkYXRhLmZyYW1lIHN1bW1hcnlfdGFibGUNCnN1bW1hcnlfdGFibGUgPC0gc2FwcGx5KGNsZWFuX2JbLCAxMTo0Ml0sIG15LnN1bW1hcnksIGFyZyA9IFQpDQojdHJhbnNwb251amVtDQp0cl9zdW1tYXJ5X3RhYmxlIDwtIHQoc3VtbWFyeV90YWJsZSkNCiNwcmludHVqZW0gdGFiZWx1DQoNCmZvcm1hdFJvdW5kKA0KICAgICAgICAgICAgZGF0YXRhYmxlKA0KICAgICAgICAgICAgICAgICAgICAgIHRyX3N1bW1hcnlfdGFibGUsDQogICAgICAgICAgICAgICAgICAgICAgY2FwdGlvbiA9ICJUYWJlbGEgMi46U3VtYXJuaSBwcmlrYXogYmV6IGJhbmFrYSBpIG9zdGFsaWggZmluYW5zaWpza2loIGluc3RpdHVjaWphIiwNCiAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXIgPSAnbm9uZScsDQogICAgICAgICAgICAgICAgICAgICAgZXh0ZW5zaW9ucyA9ICdCdXR0b25zJywgDQogICAgICAgICAgICAgICAgICAgICAgb3B0aW9ucyA9IGxpc3QoDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFnZUxlbmd0aD0xMywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkb20gPSAnQmZydGlwJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBidXR0b25zID0gYygNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ2NvcHknLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnY3N2JywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ2V4Y2VsJw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSAgDQogICAgICAgICAgICAgICAgICAgICAgKSwNCiAgICAgICAgICAgIGNvbHVtbnMgPSBjb2xuYW1lcyh0cl9zdW1tYXJ5X3RhYmxlKQ0KICAgICAgICAgICApDQpgYGANCg0KIyMjIDIuMiBOZWRvc3RhanVjZSB2cmVkbm9zdGkgIA0KDQpUcmV0aXJhbmplIG5lZG9zdGFqdWNpaCB2cmVkbm9zdGkga2FvIGtvcmFrIHUgcmF6dm9qdSBtb2RlbGEgbm9zaSBkb2RhdG51IHRlemludSBpbWFqdWNpIHUgdmlkdSBkYSBjZSBiaXRpIHBvdHJlYm5vIHRyZXRpcmF0aSBuZWRvc3RhanVjZSB2cmVkbm9zdGkgaSB1IHByb2Nlc3Ugc2Ftb2cgcHJlZHZpZGphbmphIHNvbHZlbnRub3N0aSBiYW5rZSAoYSB0byBqZSBrcmFqbmppIGNpbGogb3ZlIGFuYWxpemUpIHBvc3RvIGplIG1vZGVsIGV2YWx1aXJhbi4gU2FtaW0gdGltLCB1dmlkb20gdSBsaXRlcmF0dXJ1IG8gbmFqYm9samltIHByYWtzYW1hIHRyZXRtYW5hIG5lZG9zdGFqdWNpaCBvYnNlcnZhY2lqYSBvZGx1Y3VqZW1vIHNlIHphIHNsZWRlY2kgcG9zdHVwYWsga29qaSBqZSBwcmVkbG96ZW4gdSBrbmppemkgKkRldmVsb3BpbmcsIFZhbGlkYXRpbmcgYW5kIFVzaW5nIEludGVybmFsIFJhdGluZ3MqOiAgDQoNCiogICBSZWQgb2JzZXJ2YWNpamUgc2UgYnJpc2UgdWtvbGlrbyBuZWRvc3RhamUgdmlzZSBvZCA3NSUgcG9kYXRha2EgdSBuamVtdQ0KKiAgIEtvbG9uYSB2YXJpamFibGUgc2UgYnJpc2UgdWtvbGlrbyBpbWFqdSB2aXNlIG9kIDEwJSBuZWRvc3RhanVjaWggdnJlZG5vc3RpW14yXQ0KKiAgIFVrb2xpa28gbmVkb3N0YWplIG1hbmplIG9kIDEwJSBvYnNlcnZhY2lqZSBwb3NtYXRyYW5lIHZhcmlqYWJsZSB2cnNpIHNlIGltcHV0YWNpamEgKHphbWVuYSkgb2JzZXJ2YWNpamEgbWVkaWphbmltYSB2YXJpamFibGkuIE5hIG92YWogbmFjaW4gc2UgaXpiZWdhdmEgb3NldGxqaXZvc3QgbmEgYXV0bGFqZXJlIGtvanUgcG9zZWR1amUgc3JlZG5qYSB2cmVkbm9zdC4gUHJpIGNlbXUgc2UgbWVkaWphbmEgcG9zZWJubyBwcm9yYWN1bmF2YSB6YSB6ZHJhdmUgYSBwb3NlYm5vIHphIGR1em5pa2UgdSBzdGF0dXN1IG5laXptaXJlbmphIG9iYXZlemEuIE92bywgbWVkanV0aW0gbmlqZSBzbHVjYWoga29kIHZhbGlkYWNpb25vZyB1em9ya2EsIGthbyB0YWthdiBvbiBuZSBiaSB0cmViYW8gZGEgc2FkcnppIG5pa2FrdnUgaW5mb3JtYWNpanUgbyB0b21lIGRhIGxpIGNlIHBvc21hdHJhbmkgZHV6bmlrIHUgYnVkdWNub3N0aSBwcmVzdGF0aSBkYSBpem1pcnVqZSBzdm9qZSBvYmF2ZXplLCBzYW1pbSB0aW0gdSB2YWxpZGFjaW9ub20gdXpvcmt1IGthbyB2cmVkbm9zdCBpbnB1dGFjaWplIGtvcmlzdGltbyBtZWRpamFudSBrb21wbGV0IHZhcmlqYWJsZSwgbmV6YXZpc25vIG9kIHRvZ2EgZGEgbGkgcHJpcGFkYSBzb2x2ZW50bmltIGlsaSBuZXNvbHZlbnRuaW0gZHV6bmljaW1hLiAgDQoqICAgSW5kaWthdG9yaSBzZSB0cmFuc2Zvcm1pc3UgdSBrYXRlZ29yaWNrZSB2YXJpamFibGUgdWtvbGlrbyBwb3N0b2ppIGFwcmlvcmkgem5hbmplIG8gbmppaG92b20gem5hY2FqdSBpIHVrb2xpa28gbmUgcG9zdG9qZSBwcm9rc2kgaW5kaWthdG9yaSBrb2ppIGJpIHphbWVuaWxpIHBvc21hdHJhbmkgaW5kaWthdG9yLiAgDQoNClZhcmlqYWJsZSBrb2plIHByZWRzdGF2bGphanUgcHJvYmxlbSB1IHNtaXNsdSBwcm9jZW5hdGEgbmVkb3N0YWphbmphIHN1OiAgDQoNCiogICAqUmFjaW9fbm92Y2FuZV9saWt2aWRub3N0aV8oQ2FzaF9yYXRpbykqIC0gb3ZhIHZhcmlqYWJsYSBqZSBuYSBncmFuaWNpIHBvIGdvcmVuYXZlZGVuaW0ga3JpdGVyaWp1bWltYQ0KKiAgIFJhY2lvX29icnRhX3BvdHJheml2YW5qYV9vZF9rdXBhY2ENCiogICBSYWNpb19vYnJ0YV9wb3Nsb3ZuZV9pbW92aW5lDQoqICAgUmFzdF9FQklUREENCiogICAqU3RvcGFfcHJpbm9zYV9uYV91a3VwbmFfc3JlZHN0dmFfcHJlX29wb3Jleml2YW5qYSogLSBvdmEgdmFyaWphYmxhIGplIG5hIGdyYW5pY2kgcG8gZ29yZW5hdmVkZW5pbSBrcml0ZXJpanVtaW1hDQoqICAgUmFzdF9wcmlob2RhX29kX3Byb2RhamUNCiogICBQb2tyaWNlX25ldG9fa2FtYXRhICAgDQoNClphcGF6YW1vIGRhIHNlIGJyaXNhbmplIG5lZG9zdGFqdWNpaCBvYnNlcnZhY2lqYSBwcmVwb3J1Y3VqZSB0ZWsgcG9zdG8gc3UgaXNwdW5qZW5pIG9kcmVkamVuaSB1c2xvdmkgYmV6IG9iemlyYSBuYSB2ZWxpY2ludSB1em9ya2EsIGJyaXNhbmplIG5lZG9zdGFqdWNpaCBvYnNlcnZhY2lqYSBiaSBnZW5lcmFsbm8gdHJlYmFsbyBkYSBidWRlIHBvc2xlZG5qYSBvcGNpamEgcHJpIGNpc2Nlbmp1IHBvZGF0YWthLiAgDQpKb3MgamVkbmEgY2luamVuaWNhIGNlIGltYXRpIHVkZW8gdSBpemJvcnUgdmFyaWphYmxpLiBQcmUgc3ZlZ2EgY2V0aXJpIHBva2F6YXRlbGphIHUgbGlzdGkgc3UgZGluYW1pY2tpIGkgcHJpa2F6dWp1IHN0b3B1IHJhc3RhIG9kcmVkamVuZSB2ZWxpY2luZSwgY2ltZSBzZSBndWJpIGplZG5hIChwcnZhKSBnb2RpbmEgb2JzZXJ2YWNpamEsIHNhbWltIHRpbSBvdmEgY2V0aXJpIHBva2F6YXRlbGphIGNlIHUgcHJ2b2ogZ29kaW5pIGltYXRpIHN2ZSBuZWRvc3RhanVjZSB2cmVkbm9zdGkuIE5hdm9kaW1vIG92ZSByYWNpamU6ICANCg0KKiAgIFJhY2lvIG9icnRhIHBvdHJhxb5pdmFuamEgb2Qga3VwYWNhOyAgDQoqICAgUmFjaW8gb2JydGEgcG9zbG92bmUgaW1vdmluZTsgIA0KKiAgIFJhc3QgRUJJVERBOyAgDQoqICAgUmFzdCBwcmlob2RhIG9kIHByb2RhamUuICANCg0KT2RsdWthIG8gYnJpc2FuanUgaWxpIHphZHJ6YXZhbmp1IG92aWggdmFyaWphYmxpIGNlIHByZXZhc2hvZG5vIHphdmlzaXRpIG9kIG5qaWhvdmUgZGlza3JpbWluYXRpdm5lIG1vY2kgcGEgemF0aW0gb2QgZ29yZSBuYXZlZGVuaWgga3JpdGVyaWp1bWEuIERvZGF0bm8gcG9qYXNuamF2YW1vIGRhIGJpIHphZHJ6YXZhbmplIG92aWggdmFyaWphYmxpIHNrcmF0aWxvIGNpdGF2IHV6b3JhayB6YSBwcnZ1IGdvZGludSBvYnNlcnZhY2lqYSwgcGEgY2UgaSB2ZWxpY2luYSB1em9ya2EgYml0aSBwcmVzdWRhbiBmYWt0b3IuDQoNClByZSBwcmltZW5lIGdvcmUgbmF2ZWRlbmloIHBvc3R1cGFrYSB2YXpubyBqZSBuYXZlc3RpIGRhIGNlbW8gbWkgcmFkaXRpIHRyaSBtb2RlbGEsIHUgemF2aXNub3N0aSBvZCB2ZWxpY2luZSBkdXpuaWthLiBTYW1hIHBvZGVsYSBjZSBiaXRpIGl6dnJzZW5hIG5hIG9zbm92dSB2YXJpamFibGUgYFZlbGljaW5hYCBrb2phIHJhenZyc3RhdmEgbGljYSBwcmVtYSB1bmFwcmVkIHV0dnJkamVuaW0ga3JpdGVyaWp1bWltYSBBUFItYSB2aWRldGkgW0FQUi8i0JrRgNC40YLQtdGA0LjRmNGD0LzQuCDQt9CwINGA0LDQt9Cy0YDRgdGC0LDQstCw0ZrQtSDQuCDQs9GA0LDQvdC40YfQvdC1INCy0YDQtdC00L3QvtGB0YLQuCDQt9CwIDIwMTYuINCz0L7QtNC40L3RgyJdKGh0dHA6Ly93d3cuYXByLmdvdi5ycy/QoNC10LPQuNGB0YLRgNC4L9Ck0LjQvdCw0L3RgdC40ZjRgdC60LjQuNC30LLQtdGI0YLQsNGY0Lgv0KDQsNC30LLRgNGB0YLQsNCy0LDRmtC10L/RgNCw0LLQvdC40YXQu9C40YbQsC/QmtGA0LjRgtC10YDQuNGY0YPQvNC40LfQsNGA0LDQt9Cy0YDRgdGC0LDQstCw0ZrQtdC40LPRgNCw0L3QuNGH0L3QtdCy0YDQtdC00L3QvtGB0YLQuC5hc3B4KS4gVSBjaWxqdSB1emltYW5qYSB1IG9iemlyIHZlbGljaW5lIGl6bG96ZW5vc3RpIGtvcmlzdGljZW1vIGkgdmFyaWphYmx1IGtvamEgcHJlZHNhdmxqYSB1ZGVvIGl6bG96ZW5vc3RpIHBvc21hdHJhbm9nIGR1em5pa2EgdSBrYXBpdGFsdSBiYW5rZSBrb2phIGplIHByZW1hIG5qZW11IGl6bG96ZW5hLiBPdmEgdmFyaWphYmxhIGNlIGJpdGkgbmFrbmFkbm8gc3JhY3VuYXRhIGkgaW1hIHphIGNpbGogZGEgdXptZSB1IG9iemlyIHJhemxpY2l0IHRyZXRtYW4gcHJlbWEgZHV6bmlrdSBwcmVtYSBuamVnb3ZvaiB2ZWxpY2luaSBwb3NtYXRyYW5vIHNhIHN0YW5vdm5pc3R2YSBiYW5rZS4gQnVkdWNpIGRhIHN1IG9kcmVkamVuaSBkdXpuaWNpIHphZHV6ZW5pIGtvZCB2aXNlIGJhbmFrYSBwb3NtYXRyYWNlIHNlIHNhbW8gb25lIGJhbmtlIHUga29qaW1hIGplIGRhdGkgZHV6bmlrIG5hanZpc2UgemFkdXplbi4gT3ZvIGplIHVqZWRubyBpIHJlenVsdGF0IHJhbmlqZSBvYnJhZGUgcG9kYXRha2EgaXogS0E0IGkgUksgb2JyYXNjYSAodmlkZXRpIHNrcmlwdCA8Zm9udCBjb2xvcj1yZWQ+In5FYXJseSB3YXJuaW5nXFxuYnNfZGF0YV9wcmVwLlIiPC9mb250PikgZ2RlIHN1IG8gb3ZpbSBzbHVjYWpldmltYSB2aXNlc3RydWtlIGl6bG96ZW5vc3RpIHNhY3V2YW5lIG9ic2VydmFjaWphIGtvZCBiYW5ha2EgcHJlbWEga29qaW1hIHBvc2VkdWp1IG5hanZlY2EgZHVnb3ZhbmphLiBQcmUgcG9jZXRrYSAqdW5pdmFyaWF0ZSogYW5hbGl6ZSBwb3RyZWJubyBqZSBwcm9yYWN1bmF0aSB2ZWMgc3BvbWVudXRpIHVkZW8gaXpsb3plbm9zdGkgcG9zbWF0cmFub2cgZHV6bmlrYSB1IHJlZ3VsYXRvcm5vbSBrYXBpdGFsdSBiYW5rZS4gVG8gY2VtbyB1cmFkaXRpIHRha28gc3RvIGNlbW8gaW5wb3J0b3ZhdGkgdmVjIHByaXByZW1samVudSB0YWJlbHUgc2Egc2VyaWpvbSB2cmVkbm9zdGkgcmVndWxhdG9ybm9nIGthcGl0YWxhIGJhbmFrYS4gIA0KYGBge3J9DQojdWNpdGF2YW0gc2VyaWp1IHJlNGd1bGF0b3Jub2cga2FwaXRhbGEgemEgYmFua2UNCnJlZ3VsYXRvcnlfY2FwaXRhbCA8LSByZWFkX2RlbGltKA0KICAiQzovVXNlcnMvbWlsb3MuY2lwb3ZpYy9EZXNrdG9wL1Byb2pla3RpL0Vhcmx5IHdhcm5pbmcvUmF6dm9qbmkgZm9sZGVyL0JvdHRvbSBVcC9Lb3JhayA1L3JlZ3VsYXRvcnlfY2FwaXRhbC5jc3YiLA0KICAiOyIsDQogIGVzY2FwZV9kb3VibGUgPSBGQUxTRSwNCiAgY29sX3R5cGVzID0gY29scyhEYXR1bSA9IGNvbF9kYXRlKGZvcm1hdCA9ICIlZC4lbS4lWSIpKSwNCiAgdHJpbV93cyA9IFRSVUUNCikNCg0KI3ByaWxlcGxqdWplbSBqZSB6YSBjbGVhbl9iIHRhYmVsdQ0KY2xlYW5fYiA8LQ0KICBtZXJnZSgNCiAgY2xlYW5fYiwNCiAgcmVndWxhdG9yeV9jYXBpdGFsLA0KICBieS54ID0gYygiREFUVU0ueCIsICJNQVRJQ05JX0JST0oueCIpLA0KICBieS55ID0gYygiRGF0dW0iLCAiTUIiKQ0KICApDQoNCiNwcm9yYWN1bmF2YW0gdWRlbyBpemxvemVub3N0aSBpIG9kc3RyYW5qdWplbSBrb2xvbmUgdmlza2Ega29qZSBzdSBkb3NsZSBzYSB0YWJlbG9tIHJlZ3VsYXRvcnlfY2FwaXRhbA0KY2xlYW5fYiA8LQ0KICBjbGVhbl9iWywgdWRlb191X2thcGl0YWx1IDo9IChJWkxPWkVOT1NULnggLyBCcm9qaWxhYykgKiAxMDAwXSNza2FsaXJhbm8gemJvZyBudW1lcmlrZQ0KICBjbGVhbl9iIDwtIGNsZWFuX2JbLCBjKCJCcm9qaWxhYyIsICJJbWVuaWxhYyIsICJQb2themF0ZWxqIikgOj0gTlVMTF0NCg0KI2Npc3RpbSBzbWVjZQ0KICBybSgNCiAgICBiLA0KICAgIFByYXZuYV9mb3JtYSwNCiAgICByZWd1bGF0b3J5X2NhcGl0YWwsDQogICAgc3VtbWFyeV90YWJsZSwNCiAgICBzdW1tYXJ5X3RhYmxlMSwNCiAgICB0cl9zdW1tYXJ5X3RhYmxlDQogICAgKQ0KICAgIGdjKCkNCmBgYA0KDQpbXjFdOiBPdmRlIHNlIHRvIG5lIHZpZGkgamVyIGplIHUgbWVkanV2cmVtZW51IHByZXByYXZsamVubywgdmlkaSByYXp2b2puaSBmb2xkZXIsIGtvcmFrZSAyLDMsNS4gT3NpbSB2ZWNpaCB2cmVkbm9zdGkga29qZSBzdSBzZSBqYXZpbGUgZG9zbG8gc2UgZG8gc2F6bmFuamEgZGEgdmVsaWNpbmEgcHJhdm5paCBsaWNhIHUgQVBSIGJhemkgbmlqZSBiaWxhIHByZXJhY3VuYXRhIHBvIGtyaXRlcmlqdW1pbWEgbm92b2cgemFrb25hLCB2aWRpIFtaYWtvbiBvIHJhY3Vub3ZvZHN0dnUgU2wuIGdsYXNuaWsgUlMgYnIuIDYyMjAxM10oaHR0cDovL3d3dy5pbmZ1c2UuY28ucnMvemFrb25pL3pfcmFjdW5vdm9kc3R2b182Ml8yMDEzLnBkZikgcGEgamUgb25hIG5ha25hZG5vIHByZXJhY3VuYXRhIHUgZXhjZWxpbWEgcG9zbGUgY2VnYSBqZSBvdmFqIHNrcmlwdCBwb25vdm8gcG9rcmVudXQgdGFrbyBkYSBzZSBvdmFqIHRla3N0IGtvamkgc2kgcHJvY2l0YW8gb2Rub3NpbyBuYSByYW5panUgdmVyemlqdS4uLixJbmNlcHRpb24uIA0KDQpbXjJdOiBWaWRlY2VtbyBrYXNuaWplIGRhIG92YWoga3JpdGVyaWp1bSB6YXZpc2kgaSBvZCBpc2t1c3R2YSBzYW1vZyBhdXRvcmEsIHRha28gbmEgcHJpbWVyIE9lTkIgaSBGTUEgKDIwMDQpIHByZXBvcnVjdWp1IGJyaXNhbmplIHVrb2xpa28gbmVkb3N0YWplIHZpc2Ugb2QgMjAlIHZyZWRub3N0aSBkb2sgc21vIG92ZGUgbmF2ZWxpIGl6dm9yIGtvamkgcHJlcG9ydWN1amUgYnJpc2FuamUgdmFyaWphYmxlIHVrb2xpa28gbmVkb3N0YWplIDEwJSB2cmVkbm9zdGkuICANCg0KTmEga3JhanUgcG9nbGVkYWptbyB0YWJlbHUgY2lzY2VuamEgcG9kYXRha2E6ICANCg0KIVtUYWJlbGEgMy46IFByZWdsZWQgb2JyYWRlIHBvZGF0YWthIG9kIHBvY2V0bmloIHBhIGRvIHBvZGF0YWthIGtvamkgdWxhemVdKHRhYmVsYS5wbmcpeyNpZCAuY2xhc3Mgd2lkdGg9MTUwMCBoZWlnaHQ9MTAwMH0NCg0KDQojIyAzLiAqIlVuaXZhcmlhdGUiKiBhbmFsaXphICANCl9fX19fX19fX19fX19fX19fX19fICANCjxwIHN0eWxlPSJjb2xvcjpncmF5O21hcmdpbi1sZWZ0OiA0MHB4O21hcmdpbi1yaWdodDogNDBweDt0ZXh0LWFsaWduOmp1c3RpZnk7Y29sb3I6Z3JheSI+IERvIHNhZGEgbmlzbW8gam9zIHV2ZWsgcmF6bWF0cmFsaSBrb250aW51YWxuZSB2YXJpamFibGUsIHJhemxvZyBqZSBiaW8gc3RvIHV6b3JhayBqb3MgdXZlayBuaWplIGJpbyBwb2RlbGplbiBuYSB0cmkgcG9kdXpvcmthIHUgemF2aXNub3N0aSBvZCB2ZWxpY2luZSBkdXpuaWthLiBQcmUgcG9jZXRrYSAqdW5pdmFyaWF0ZSogYW5hbGl6ZSByYXpkdm9qaWNlbW8gdXpvcmFrIG5hIHRyaSBkZWxhLiBQb3NlYm5vIGNlIHNlIGV2YWx1aXJhdGkgbW9kZWxpIHphIG1pa3JvIGkgbWFsYSwgc3JlZG5qYSBpIHZlbGlrYSBwcmVkdXplY2EuIFRha29kamUsIHRyZXRtYW4gbmVkb3N0YWp1Y2loIHZyZWRub3N0aSBqZSBzYW1vIGRlc2tyaXB0aXZubyBuYXZlZGVuIHUgc21pc2x1IG1ldG9kb2xvc2tvZyBwcmF2Y2EgdSBrb20gY2Ugc2UgaWNpIHByaSBvYnJhZGkuIFN2ZSBvdmUgYW5hbGl6ZSBpIG9uZSBrb2plIHNsZWRlIGNlIHNlIG9iYXZpdGkgcG9qZWRpbmFjbm8gemEgc3Zha3UgZ3J1cHUgZHV6bmlrYSBwb25hb3NvYi4gUHJlIG5lZ28gc3RvIHNlIHV6b3JhayByYXpkdm9qaSwgdSBvdm9qIHNla2NpamksIHVrcmF0a28gY2UgYml0aSBvcGlzYXRpIHJhY2lqaSBrb2ppIHN1IGtvcmlzY2VuaSwgbmppaG92YSBla29ub21za2EgbG9naWthIGkgb2Nla2l2YW51IHZlenUgc2EgdmVyb3ZhdG5vY29tICpkaWZvbHRhKiwgamVyIGNlIHNlIGlzdGkgc2V0IHJhY2lqYSBrb3Jpc3RpdGkgdSBzdmEgdHJpIHNsdWNhamEuIFBvIG9waXN1IHJhY2lqYSwgdSBuYXN0YXZrdSBvdmUgc2VrY2lqZSwgY2Ugc2UgaXNwaXRhdGkgYnJvaiBuZWRvc3RhanVjaWggdnJlZG5vc3RpIGkgbmppaG92IHRyZXRtYW4sIHByaXN1dG5vc3QgYXV0bGFqZXJhIGkgbmppaG92IHRyZXRtYW4sIHJhZG5hIGhpcG90ZXphLCBtb25vdG9ub3N0LCBtb2MgZGlza3JpbWluYWNpamUgaSBrb3JlbGFjaWphIHphIHN2YWtpIG9kIHRyaSBtb2RlbGEuIFN2aSBwcmV0aG9kbm8gbmF2ZWRlbmkgcG9zdHVwY2kgaW1hanUgemEgY2lsaiBzdG8gYm9sanUgcHJlZCBzZWxla2NpanUgdmFyaWphYmxpIHByZWQgdWx6YWsgdSB6YXZyc251IGZhenUgKm11bHRpdmFyaWF0ZSogYW5hbGl6dSBnZGUgY2UgKnN0ZXB3aXNlKiBwcm9jZWR1cm9tIGJpdGkgaXphYnJhbmkga29uYWNuaSBtb2RlbGk8L3A+ICANCg0KIyMjIDMuMSBGaW5hbnNpanNraSByYWNpamksIGVrb25vbXNrYSBsb2dpa2EgaSByYWRuYSBoaXBvdGV6YSAgDQoNCkthbyBwb2xhem5hIG9zbm92YSBwb3NsbyBzZSBvZCBwZXQgZ3J1cGEgcG9rYXphdGVsamEga29qaSBiaSwgaWRlYWxubywgdHJlYmFsbyBkYSBuYW0gZGFqdSBpbmZvcm1hY2lqdSBvOiAgDQoNCiogICBMaWt2aWRub3N0aQ0KKiAgIFNvbHZlbnRub3N0aQ0KKiAgIFByb2ZpdGFiaWxub3N0aQ0KKiAgIFBvc2xvdm5lIGFrdGl2bm9zdGkNCiogICBPc3RhbGkgcG9rYXphdGVsamkga29qZSBqZSB0ZXNrbyBzdnJzdGF0aQ0KDQoNClBva2F6YXRlbGppLCBuamlob3ZhIHByaXBhZG5vc3QgZ3J1cGkgaSBoaXBvdGV6YSBla29ub21za2UgbG9naWNub3N0aSBuamlob3ZlIHJlbGFjaWplIHNhIHZlcm92YXRub2NvbSBuYXN0dXBhbmphIG5laXptaXJlbmphIG9iYXZlemEgamUgcHJpa2F6YW5hIHUgc2xlZGVjb2ogdGFiZWxpOiAgDQoNCiFbVGFiZWxhIDQuOiBQb2xhem5pIHJhY2lqaSBrb2ppIHVsYXplIHUgdW5pdmFyaWF0ZSBhbmFsaXp1XSh0YWJlbGEyLnBuZyl7I2lkIC5jbGFzcyB3aWR0aD0xNTAwIGhlaWdodD0xMDAwfQ0KDQoNCg0KIyMjIDMuMiAqIlVuaXZhcmlhdGUiKiBhbmFsaXphICANClJhemR2YWphbW8gdXpvcmFrIG5hIHRyaSBwb2RncnVwZToNCmBgYHtyfQ0KI2tyZWlyYW0gdHJpIG5vdmUgdGFiZWxlIHNhIGtvamltYSBkYWxqZSByYWRpbQ0Kc21hbGwgPC0gY2xlYW5fYltWZWxpY2luYSA8PSAyLCBdDQptZWRpdW0gPC0gY2xlYW5fYltWZWxpY2luYSA9PSAzLCBdDQpsYXJnZSA8LSBjbGVhbl9iW1ZlbGljaW5hID09IDQsIF0NCiNicmlzZW0gcHJlb3N0YWxlIG1lZGp1a29yYWtlDQpybShjLCBOQlNfZGF0YSkNCmdjKCkNCmBgYA0KDQpQcnZvIMSHZW1vIGRldGFsam5vIGFuYWxpemlyYXRpICoqdmVsaWthIHByZWR1emVjYSoqIChwb2RhY2kgYGxhcmdlYCkgcG/EjWV2xaFpIG9kIHN2aWggZ29yZSBuYXZlZGVuaWgga29yYWthIHUgYW5hbGl6aSwgdGFrbyBkYSDEh2Ugb3ZhaiBkZW8gaW1hdGkgdHJpIHBvZGdydXBlLCB6YXZpc25vIG9kIHNhbWUgdmVsacSNaW5lIGR1xb5uaWthLiBTYW1pbSB0aW0gaSBrcmXEh2VtbyB1IGRldGFsam51IGFuYWxpenUgc2FkYS4uLiAgDQoNCjxoMyBzdHlsZT0iY29sb3I6cmVkOyI+VW5pdmFyaWF0ZSBhbmFsaXphIHZlbGlraWggcHJlZHV6ZcSHYTwvaDM+DQoNClBvdHJlYm5vIGplIHByZSBzdmVnYSByYXpkdm9qaXRpIHV6b3JhayBuYSB2YWxpZGFjaW9uaSBpIGVzdGltYWNpb25pLiBVIG5hY2VsdSBwcmF2aWxvIGplIGRhIHNlIHV6b3JhayBkZWxpIG5hIDcwOjMwIG5hIHN0cmFudSBlc3RpbWFjaWplLCBtZWRqdXRpbSB1a29saWtvIGt1YnVyaW1vIHNhIHBvZGFjaW1hIExlbWVzaG93IHUgc3ZvbSBba3Vyc3UgbyBsb2dpc3RpY2tvaiByZWdyZXNpamldKGh0dHBzOi8vd3d3LmNhbnZhcy5uZXQvYnJvd3NlL29zdS9jb3Vyc2VzL2FwcGxpZWQtbG9naXN0aWMtcmVncmVzc2lvbikgYXJndW1lbnR1amUgZGEgamUgbW5vZ28gYml0bmlqZSBkYSBpbWFtbyBrb21wbGV0bmlqaSB1em9yYWsgemEgZXN0aW1hY2lqdSwgdGFrbyBkYSBjZW1vIHNlIHZvZGl0aSBvdm9tIGxvZ2lrb20gaSB1IG5hc2VtIHNsdWNhanUuICANClBhLCBwb2NuaW1vLg0KYGBge3J9DQojaXpyYWN1bmFtIGJyb2ogcmVkb3ZhDQpicm9qLnJlZC5scmdlPC1ucm93KGxhcmdlKQ0KYnJvai5kaWZvbHRhLmxyZ2U8LXN1bShhcy5udW1lcmljKGxhcmdlJGRlZmF1bHQueT09MSkpDQpwcm9jZW5hdC5kaWZvbHRhPC1icm9qLmRpZm9sdGEubHJnZS9icm9qLnJlZC5scmdlDQpgYGANCkRha2xlIHUgbmFqYm9samVtIHNsdWNhanUsIG5lIHJhY3VuYWp1Y2kgbWlzc2luZyB2YWx1ZSBpbWFtbyBgciBicm9qLmRpZm9sdGEubHJnZWAgZGlmb2x0YSwgc3RvIG5hbSBkZWx1amUga2FvIGplZHZhIGRvdm9sam5vLCB1a29saWtvIGJpc21vIHphZHJ6YWxpIDMwJSBiaWxpIGJpc21vIG5hIGdyYW5pY2kuIE1lZGp1dGltIGRhIGJpc21vIHNlIG9zaWd1cmFsaSB6YWRyemFjZW1vIDc1JSwgdGltZSBvcGV0IGltYW1vIGRvdm9sam5vIGRpZm9sdGEgemEgdmFsaWRhY2lqdSAob2tvIDQwKSwgb3ZkZSBzYW0gc2Ugdm9kaW8gc2F2ZXRvbSBwcm9mZXNvcmEgTGVtZXNob3ctYSBrb2ppIGthemUgZGEgc2UgdSBvdm9qIHNpdHVhY2lqaSB1dmVrIHBva3VzYSB6YWRvdm9saml0aSAqdHJhaW5pbmcgc2FtcGxlKi4gUyBkcnVnZSBzdHJhbmUgcmFjaW8gbmVzb2x2ZW50bmloIHUgdWt1cG5pbSBkdXpuaWNpbWEgbW96ZSBpbWF0aSByYXpsaWNpdGUgdnJlZG5vc3RpLCB0ai4gbmUgcG9zdG9qaSBrb25zZW56dXMgdSBsaXRlcmF0dXJpIG8gb3ZvaiB2cmVkbm9zdGkuIE92ZGUgYmlyYW1vIGRhIHphZHJ6aW1vIHRyZW51dGFuIHJhY2lvIHUgdXpvcmt1IHRha28gZGEgY2VtbyB1emV0aSA3NSUgb2QgKHNvbHZlbnRuaWggaSBuZXNvbHZlbnRuaWgpIGR1em5pa2EgemFqZWRubyBpIHJhZGl0aSBlc3RpbWFjaWp1IG5hIG5qZW11LiBPdmltIHBvc3R1cGtvbSBzbW8gaXpiZWdsaSBwb3N0dXBhayBrYWxpYnJhY2lqZSBqZXIgc21vIHUgKnRyYWluaW5nKiB1em9ya3UgemFkcnphbGkgc3R2YXJudSBmcmVrdmVuY2lqdSBkZWZhdWx0YSwgY2l0YWosIHZlcm92YXRub2N1IGRlZm91bHRhLiBKZWRhbiBwcm9ibGVtIGtvamkgc2UgbW96ZSBwb3RlbmNpamFsbm8gamF2aXRpIGplIHZhbGlkbm9zdCBIb3NtZXLigJNMZW1lc2hvdyB0ZXN0YSBzYSA0MCBkaWZvbHRhLiANCg0KYGBge3J9DQpzZXQuc2VlZCg2MCkNCiN6Ym9nIHJlcHJvZHVrY2lqZQ0Kc2FtcGxlLmxyZyA8LQ0Kc2FtcGxlKGJyb2oucmVkLmxyZ2UsIHNpemUgPSByb3VuZCgwLjc1ICogYnJvai5yZWQubHJnZSwgMCkpDQpscmdlLnRyYWluaW5nIDwtIGxhcmdlW3NhbXBsZS5scmcsIF0NCmxyZ2UudGVzdCA8LSBsYXJnZVstc2FtcGxlLmxyZywgXQ0KYGBgDQoNCg0KIyMjIyoqVGVzdGlyYW5qZSByYWRuZSBoaXBvdGV6ZSwgZGlza3JpbWluYXRpdm5vc3RpLCBrb3JlbGFjaW9uZSBtYXRyaWNlKiogIA0KDQpKb3MgamVkbm9tIGNlbW8gcHJlZ2xlZGF0aSB2YXJpamFibGU6DQoNCmBgYHtyfQ0KI3JwaXZvdFRhYmxlKGxyZ2UudHJhaW5pbmcpDQpzdW1tYXJ5X3RhYmxlPC10KHNhcHBseShscmdlLnRyYWluaW5nWywxMTo0M10sbXkuc3VtbWFyeSxhcmc9VCkpDQp0cl9zdW1tYXJ5X3RhYmxlPC10KHN1bW1hcnlfdGFibGUpDQpmb3JtYXRSb3VuZCgNCiAgICAgICAgICAgIGRhdGF0YWJsZSgNCiAgICAgICAgICAgICAgICAgICAgICBzdW1tYXJ5X3RhYmxlLGNhcHRpb24gPSAiVGFiZWxhIDMuOlN1bWFybmkgcHJpa2F6IiwNCiAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXIgPSAnbm9uZScNCiAgICAgICAgICAgICAgICAgICAgICApLA0KICAgICAgICAgICAgY29sdW1ucyA9IGNvbG5hbWVzKHN1bW1hcnlfdGFibGUpDQogICAgICAgICAgICkNCmBgYA0KDQpHZW5lcmFsbmEgcHJlcG9ydWthIGplIGRhIHNlIHJhZG5hIGhpcG90ZXphIHRlc3RpcmEgcHJlIHRyZXRtYW5hIG5lZG9zdGFqdcSHaWggdnJlZG5vc3RpIGJ1ZHXEh2kgZGEgxIdlIHNlIG5lZG9zdGFqdcSHZSB2cmVkbm9zdGkgcG9wdW5qYXZhdGkgdXNsb3ZubyBvZCBzdGFuamEgc29sdmVudG5vc3RpIGR1em5pa2EuIFNhbWltIHRpbSBvdmRlIGNlbW8ga2FvIHBydmkgdmlkIHNlbGVrY2lqZSBpc3BpdGF0aSByYWRudSBoaXBvdGV6dSBrYWtvIGtvbnRpbnVhbG5paCB0YWtvIGkga2F0ZWdvcmlja2loIHZhcmlqYWJsaS4gUG/EjWXEh2VtbyBzYSBrb250aW51YWxuaW1bXjNdIGkgYW5hbGl6dSByYWRpdGkgdSBwYXJ1IHNhIHByb3Zlcm9tIGRpc2tyaW1pbmF0aXZub3N0aSB2YXJpamFibGkuIEpvxaEgdSBUYWJlbGkgMyB2aWRpbW8gdmVsaWthIG9kc3R1cGFuamEgc3JlZG5qZSB2cmVkbm9zdGkgb2QgbWVkaWphbmUgaSB0cmltb3Zhbm9nIHByb3Nla2EsIGJ1ZHVjaSBkYSBqZSBwcm9zZWsga2FvIG1lcmEgY2VudHJhbG5lIHRlbmRlbmNpamUgb3NldGxqaXZhIG5hIGF1dGxhamVyZSBvZGx1Y3VqZW1vIHNlIGRhIHBvc21hdHJhbW8gbWVkaWphbnUgaSB0cmltb3ZhbiBwcm9zZWssIHNhbWltIHRpbSBtb2d1Y25vc3QgKnQgdGVzdGEqIG90cGFkYS4gRGFsamUsIHNsZWRlY2kgcHJlcG9ydWtlIGl6IGxpdGVyYXR1cmUgb3ZhaiBkZW8gYW5hbGl6ZSBvc2xvbml0aSBuYSBwb3NtYXRyYW5qZSBib3ggcGxvdG92YSBpIGJpY2UgZG9wdW5qZW4gZGlza3JpbWluYXRpdm5vbSBhbmFsaXpvbSBBVVJPQy1hLiBQcmkgdGVzdGlyYW5qdSBrb3JlbGFjaWphIHByYWcgc2VsZWtjaWplIHBvc3RhdmxqYW1vIG5hIDAuNSBpIG9kIGR2ZSBiaXJhbW8gb251IHZhcmlqYWJsdSBrb2phIGltYSB2ZWN1IGRpc2tyaW1pbmFjaW9udSBtb2MuIA0KDQpLb2Qga2F0ZWdvcmlja2loIHZhcmlqYWJsaSBwb3NtYXRyYWNlbW8gdGFiZWxlIGZyZWt2ZW5jaWphIHRhbW8gZ2RlIHRvIGJ1ZGUgaW1hbG8gc21pc2xhIGkgc3Byb3Zlc3RpIENoaS1zcXVhcmVkIHRlc3QuIE92b20gcHJpbGlrb20gcG90cmVibm8gamUgaSBwcmVncnVwaXNhdGkgb3ZlIHZhcmlqYWJsZSB0YWtvIGRhIGJ1ZHUgemFkb3ZvbGplbmkga3JpdGVyaWp1bWk6IA0KDQoqICAgYnJvaiAqZGlmb2x0YSogcG8ga2F0ZWdvcmlqaSBrYXRlZ29yaWNrZSB2YXJpamFibGUgbW9yYSBiaXRpIG1pbmltdW0gNQ0KKiAgIHVrdXBhbiBicm9qIGR1em5pa2EgcG8ga2F0ZWdvcmlqaSBrYXRlZ29yaWNrZSB2YXJpamFibGUgbW9yYSBiaXRpIHZlY2kgb2Qgc3RvDQoqICAgcHJhdmlsbyAxIHUgMTAsIHphIHN2YWtpaCAxMCBkaWZvbHRhIG1vxb5lbW8gZG9kYXRpIGplZG51IG9iamHFoW5qYXZhanXEh3UsIG92byBwcmF2aWxvIG5hbSBzbHV6aSBzYW1vIGthbyB2b2RpbGphDQoqICAgKmRlZmF1bHQgcmF0ZSogbW9yYSBiaXRpIHN0YXRpc3RpY2tpIHJhemxpY2l0IG9kICpkZWZhdWx0IHJhdGUqLWEgdWt1cG5vZyB1em9ya2EsIGluYWNlIHNlIHZyc2kgcHJlZ3J1cGFjaWphDQoqICAgaWFrbyBjZW1vIGlzcGl0YXRpIGhpcG90ZXp1IHNhZ2xlZGF2YW5qZW0gdGFiZWxhIGZyZWt2ZW5jaWphLCBwb3NsZWRuanUgcmVjIGNlIG5hbSBkYXRpIHNhbWkgbW9kZWwgaSBuamVnb3ZlICpwKiB2cmVkbm9zdGksIG9kbm9zbm8gKmxpa2VsaWhvb2QgcmF0aW8qIHRlc3QgICANCg0KUHJ2byBwcmVnbGVkYWptbyBzYW11IGRpc3RyaWJ1Y2lqdSBqb3MgamVkbm9tLCBtYWRhIHN1IG5la2Ugc3R2YXJpIHZlYyBqYXNuZSBpeiBUYWJlbGUgMyBoYWpkZSBpcGFrIGRhIHBvZ2xlZGFtby4gIA0KUHJ2byBrcmVpcmFtbyBmdW5rY2lqdSB6YSBwbG90aXJhbmplOiBxcSBwbG90YSwgYm94IHBsb3RhLCBwb3JlZGplbmphIGd1c3RpbmEgdmVyb3ZhdG5vY2UgKGtlcm5lbGEgZW1waXJpc2tpaCBkaXN0cmlidWNpamEgdmVyb3ZhdG5vY2UpIGkga29uYWNubyB6YSBwcm92ZXJ1IGRpc2tyaW1pbmFjaWplIFJPQyBrcml2ZS4NCmBgYHtyfQ0KI2RlbGltbyB1em9yYWsgbmEga29udGludWFsbmUgaSBrYXRlZ29yaWNrZQ0KbHJnZS50cmFpbmluZy5jb250aW51YWxuZTwtbHJnZS50cmFpbmluZ1ssYyg3LDYsMTEsMTM6NDMpXQ0KbHJnZS50cmFpbmluZy5rYXRlZ29yaWNrZTwtbHJnZS50cmFpbmluZ1ssYyg3LDgsOSwxMCwxMildDQpscmdlLnRlc3QuY29udGludWFsbmU8LWxyZ2UudGVzdFssYyg3LDYsMTEsMTM6NDMpXQ0KbHJnZS50ZXN0LmthdGVnb3JpY2tlPC1scmdlLnRlc3RbLGMoNyw4LDksMTAsMTIpXQ0KDQoNCnBsb3Rpbmc8LWZ1bmN0aW9uKGRhdGFmcmFtZSwgcHJlZGljdG9yX2NvbCwgZGVmYXVsdF9jb2x1bW5fY29sLG49Myl7DQogIA0KICAjdHJhbnNmb3JtYWNpamEgcG9kYXRha2EgDQogIGRhdGFmcmFtZT1hcy5kYXRhLmZyYW1lKGRhdGFmcmFtZSkNCiAgZGF0YTwtZGF0YS5mcmFtZShwcmVkaWN0b3I9ZGF0YWZyYW1lWyxwcmVkaWN0b3JfY29sXSwNCiAgICAgICAgICAgICAgICAgICBkZWZhdWx0X2NvbHVtbj1mYWN0b3IoZGF0YWZyYW1lWyxkZWZhdWx0X2NvbHVtbl9jb2xdKSkNCiAgZGF0YTwtbmEub21pdChkYXRhKQ0KICANCiNkZW5zaXR5IHBsb3QjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCiAgZGVuc2l0eTwtZ2dwbG90KGRhdGEsIGFlcyhwcmVkaWN0b3IsIGZpbGw9ZmFjdG9yKCBkZWZhdWx0X2NvbHVtbikpKSArIA0KICBnZW9tX2RlbnNpdHkoYWxwaGE9LjUpICsgDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoJyM5OTk5OTknLCcjRTY5RjAwJykpICsgDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikreGxpbShxdWFudGlsZShkYXRhJHByZWRpY3RvcixjKDAuMDUsMC45NSksbmEucm0gPSBUKSkNCg0KI2JveHBsb3QjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQpib3hfcGxvdDwtZ2dwbG90KGRhdGEsIGFlcyh5PXByZWRpY3RvciwgeD0gZGVmYXVsdF9jb2x1bW4sIGZpbGw9ZGVmYXVsdF9jb2x1bW4pKSsNCiAgZ2VvbV9ib3hwbG90KGFscGhhPTAuNSkNCiAgIyBjb21wdXRlIGxvd2VyIGFuZCB1cHBlciB3aGlza2Vycw0KeWxpbTEgPSBib3hwbG90LnN0YXRzKGRhdGEkcHJlZGljdG9yKSRzdGF0c1tjKDEsIDUpXQ0KICAjIHNjYWxlIHkgbGltaXRzIGJhc2VkIG9uIHlsaW0xDQpib3hfcGxvdCA9IGJveF9wbG90ICsgY29vcmRfY2FydGVzaWFuKHlsaW0gPSB5bGltMSpuKSsgDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoJyM5OTk5OTknLCcjRTY5RjAwJykpDQoNCiNyb2MgY3VydmUgcGxvdCMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQpST0NfcGxvdCA8LQ0KICBnZ3Bsb3QoZGF0YSwgYWVzKG0gPSBwcmVkaWN0b3IsIGQgPSBhcy5udW1lcmljKGRlZmF1bHRfY29sdW1uKSkpICsgZ2VvbV9yb2MoKSArDQogIGdlb21fYWJsaW5lKGludGVyY2VwdCA9IDAsDQogICAgICAgICAgICAgIHNsb3BlID0gMSwNCiAgICAgICAgICAgICAgY29sb3IgPSAncmVkJykNCg0KcmVzdWx0IDwtIGF1YyhkYXRhJGRlZmF1bHRfY29sdW1uLCBkYXRhJHByZWRpY3RvcikNCg0KYSA9IHBhc3RlKCJBcmVhIHVuZGVyIHRoZSBjdXJ2ZToiLA0KICAgICAgICAgIHJvdW5kKGNpKHJlc3VsdClbWzFdXSwgMyksDQogICAgICAgICAgIiwgIiwNCiAgICAgICAgICByb3VuZChyZXN1bHQsIDMpLA0KICAgICAgICAgICIsICIsDQogICAgICAgICAgcm91bmQoY2kocmVzdWx0KVtbM11dLCAzKSkNCg0KUk9DX3Bsb3QgPC0gUk9DX3Bsb3QgKyBsYWJzKHRpdGxlID0gYSkNCg0KI1FRIHBsb3QNCg0KcXMgPSBzZXEoMC4wMDEsIDAuOTk5LCBieT0wLjAwMSkNCmRmLnFzID0gZGF0YS5mcmFtZShxdWFudGlsZS5QID0gcXMsDQogICAgICAgICAgICAgICAgICAgcS52YWwuTm9ybWFsID0gcW5vcm0ocXMsbWVhbihkYXRhJHByZWRpY3Rvciksc2QoZGF0YSRwcmVkaWN0b3IpKSwNCiAgICAgICAgICAgICAgICAgICBxLnZhbC5YID0gcXVhbnRpbGUoZGF0YSRwcmVkaWN0b3IscXMpKQ0KUVFfcGxvdD1nZ3Bsb3QoZGYucXMsIGFlcyhxLnZhbC5Ob3JtYWwsIHEudmFsLlgpKSsNCiAgZ2VvbV9wb2ludChjb2w9JyM5OTk5OTknLCBjZXg9MikrDQogIGdlb21fbGluZShjb2w9JyM5OTk5OTknLCBzaXplPTAuNzUpKw0KICBnZW9tX2FibGluZShwb3NpdGlvbj0iaWRlbnRpdHkiKQ0KDQpwbG90X2dyaWQoZGVuc2l0eSxib3hfcGxvdCxST0NfcGxvdCxRUV9wbG90LGFsaWduID0gImgiLCBuY29sID0gNCkNCg0KfQ0KDQoNCmBgYA0KDQojIyMjS3JlxIdlbW8gc2Egb3Bpc29tIHN2YWtlIHZhcmlqYWJsZSBwb25hb3NvYjoNCiMjTmVwcmVraWRuZSBwcm9tZW5saml2ZToNCiMjIyNVZGVvIGlzcHJhdmtlIHUgdWt1cG5pbSBrcmVkaXRpbWEgIA0KX19fX19fX19fX19fX19fX19fX19fXw0KDQpgYGB7cixmaWcud2lkdGg9MTgsZmlnLmhlaWdodD0zfQ0KI2RlZmluaXNlbSBmdW5rY2lqdSB6YSBwbG90b3ZhbmplDQoNCnBsb3RpbmcobHJnZS50cmFpbmluZyw2LDcpDQoNCmBgYA0KVmlkaW1vIGRhIGRpc3RyaWJ1Y2lqZSBvZHN0dXBhanUgZGFsZWtvIG9kIG5vcm1hbG5lLCBkYWxqZSBwcmVrbGFwYW5qZSBkaXN0cmlidWNpamEgc29sdmVudG5paCB1IG5lc29sdmVudG5paCBkdXpuaWthIGplIHJhem9jYXJhdmFqdWNlLCBwb3N0b2ppIDcgYXV0bGFqZXJhIGtvamkgaW1hanUgbmVsb2dpY25lIHZyZWRub3N0aSBrb2ppIHZ1a3UgcG9yZWtsbyBpeiByayBvYnJhc2NhLiBJYWtvIGJveCBwbG90IHBva2F6dWplIG9kcmVkamVuaSBzdGVwZW4gZGlza3JpbWluYWNpamUgdSBzbWlzbHUgZGEgc3Ugc29sdmVudG5pIGR1em5pY2kgbWFuamUgaXNwcmF2bGplbmkgb2QgbmVzb2x2ZW50bmloLCBnZW5lcmFsbm8gUk9DIGtyaXZhIHBva2F6dWplIGRhIGplIGRpc2tyaW1pbmFjaWphIG1hcmdpbmFsbmEgaWFrbyBqZSB6bmFjYWpuYSBuYSBuaXZvdSBwb3ZlcmVuYWogb2QgOTUlLCBpcGFrLCB6bmFjYWpub3N0IGplIG1hcmdpbmFsbmEuIEF1dGxhamVyaSBpbWEgaWgsIGltYSBpaCBtbm9nby4gQnVkdWNpIGRhIGNlIHNsaWNubyBiaXRpIGkgc2Egb3N0YWxpbSB2YXJpamFibGFtYSBrcmVpcmFtbyB0YWtzYXRpdmFuIG9waXMgdSB2aWR1IGJ1bGV0YSB6YSBzdmFrdSB2YXJpamFibHUga2FvIHN0byBzbGVkaSB6YSBvdnU6ICANCg0KKiAgIFJhZG5hIGhpcG90ZXphLW5pc21vIHBvc3RhdmlsaSByYWRudSBoaXBvdGV6dSB6YSBvdnUgdmFyaWphYmx1DQoqICAgRGlza3JpbWluYXRpdm5vc3QgLW5lIHBvc3RvamkgbmEgOTUlIHNpZ3Vybm9zdGkgDQoqICAgYXV0bGFqZXJpIC0gbmFyYXZubyBpbWEgaWggaW1hDQoqICAgbm9ybWFsbm9zdCAtIG1hIGRhLi4uDQogDQogIA0KIyMjI0Jyb2ogemFwb3NsZW5paCAgDQpfX19fX19fX19fX18NCmBgYHtyLGZpZy53aWR0aD0xOCxmaWcuaGVpZ2h0PTN9DQojZGVmaW5pc2VtIGZ1bmtjaWp1IHphIHBsb3RvdmFuamUNCg0KcGxvdGluZyhscmdlLnRyYWluaW5nLDExLDcpDQoNCmBgYA0KKiAgIFJhZG5hIGhpcG90ZXphLW5pc21vIHBvc3RhdmlsaSByYWRudSBoaXBvdGV6dSB6YSBvdnUgdmFyaWphYmx1DQoqICAgRGlza3JpbWluYXRpdm5vc3QgLSBuZW1hIGplIA0KKiAgIGF1dGxhamVyaSAtIG5hcmF2bm8gaW1hIGloDQoqICAgbm9ybWFsbm9zdCAtIG1hIGRhLi4uDQoNCiMjIyNSaWdvcm96bmkgcmFjaW8gcmVkdWtvdmFuZSAobW9uZXRhcm5lKSBsaWt2aWRub3N0aSAgDQpfX19fX19fX19fX18NCmBgYHtyLGZpZy53aWR0aD0xOCxmaWcuaGVpZ2h0PTN9DQojZGVmaW5pc2VtIGZ1bmtjaWp1IHphIHBsb3RvdmFuamUNCg0KcGxvdGluZyhscmdlLnRyYWluaW5nLDEzLDcpDQoNCmBgYA0KKiAgIFJhZG5hIGhpcG90ZXphLXphZG92b2xqZW5hLCB2ZWNpIGRpZm9sdCBrb2QgbWFuamloIHZyZWRub3N0aQ0KKiAgIERpc2tyaW1pbmF0aXZub3N0IC0gaW1hIG5hIDk1JSB6bmFjYWpub3N0aSANCiogICBhdXRsYWplcmkgLSBuYXJhdm5vIGltYSBpaA0KKiAgIG5vcm1hbG5vc3QgLSBtYSBkYS4uLiAgDQoNCiMjIyNSYWNpbyBub3ZjYW5lIGxpa3ZpZG5vc3RpIChDYXNoX3JhdGlvKSAgDQpfX19fX19fX19fX19fXw0KYGBge3IsZmlnLndpZHRoPTE4LGZpZy5oZWlnaHQ9M30NCiNkZWZpbmlzZW0gZnVua2NpanUgemEgcGxvdG92YW5qZQ0KDQpwbG90aW5nKGxyZ2UudHJhaW5pbmcsMTQsNykNCg0KYGBgDQoqICAgUmFkbmEgaGlwb3RlemEtemFkb3ZvbGplbmEsIHZlY2kgZGlmb2x0IGtvZCBtYW5qaWggdnJlZG5vc3RpDQoqICAgRGlza3JpbWluYXRpdm5vc3QgLSBpbWEgbmEgOTUlIHpuYWNham5vc3RpICBpIG9iZWNhdmEhISENCiogICBhdXRsYWplcmkgLSBuYXJhdm5vIGltYSBpaA0KKiAgIG5vcm1hbG5vc3QgLSBtYSBkYS4uLiAgDQoNCg0KDQojIyMjT3BzdGkgcmFjaW8gbGlrdmlkbm9zdGkgIA0KX19fX19fX19fX18NCmBgYHtyLGZpZy53aWR0aD0xOCxmaWcuaGVpZ2h0PTN9DQojZGVmaW5pc2VtIGZ1bmtjaWp1IHphIHBsb3RvdmFuamUNCg0KcGxvdGluZyhscmdlLnRyYWluaW5nLDE1LDcpDQoNCmBgYA0KKiAgIFJhZG5hIGhpcG90ZXphLW5lemFkb3ZvbGplbmEsIHZlY2kgZGlmb2x0IGtvZCB2ZWNpaCB2cmVkbm9zdGkNCiogICBEaXNrcmltaW5hdGl2bm9zdCAtIG5lbWEgbmEgOTUlIHpuYWNham5vc3RpICBpIHRvIHRpIGplISEhDQoqICAgYXV0bGFqZXJpIC0gbmFyYXZubyBpbWEgaWgNCiogICBub3JtYWxub3N0IC0gbWEgZGEuLi4gIA0KDQojIyMjU3RlcGVuX3phZHV6ZW5vc3RpICANCl9fX19fX19fX19fX19fX18NCmBgYHtyLGZpZy53aWR0aD0xOCxmaWcuaGVpZ2h0PTN9DQojZGVmaW5pc2VtIGZ1bmtjaWp1IHphIHBsb3RvdmFuamUNCg0KcGxvdGluZyhscmdlLnRyYWluaW5nLDE2LDcpDQoNCmBgYA0KDQoqICAgUmFkbmEgaGlwb3RlemEtemFkb3ZvbGplbmEsIHZlY2kgZGlmb2x0IGtvZCB2ZWNpaCB2cmVkbm9zdGkNCiogICBEaXNrcmltaW5hdGl2bm9zdCAtIGltYSBuYSA5NSUgem5hY2Fqbm9zdGkhISENCiogICBhdXRsYWplcmkgLSBuYXJhdm5vIGltYSBpaA0KKiAgIG5vcm1hbG5vc3QgLSBtYSBkYS4uLg0KDQojIyMjSW50ZXJlc3QgQ292ZXJhZ2UgUmF0aW8gIA0KX19fX19fX19fX19fX19fX18NCmBgYHtyLGZpZy53aWR0aD0xOCxmaWcuaGVpZ2h0PTN9DQojZGVmaW5pc2VtIGZ1bmtjaWp1IHphIHBsb3RvdmFuamUNCg0KcGxvdGluZyhscmdlLnRyYWluaW5nLDE3LDcpDQoNCmBgYA0KKiAgIFJhZG5hIGhpcG90ZXphLXphZG92b2xqZW5hLCB2ZWNpIGRpZm9sdCBrb2QgbWFuamloIHZyZWRub3N0aQ0KKiAgIERpc2tyaW1pbmF0aXZub3N0IC0gaW1hIG5hIDk1JSB6bmFjYWpub3N0aSAgaSBvayBqZSwgbW96ZSBkYSBwcm9kamUsIG1hZGEga3JpdnVkYSBzdG8gbmlqZSBkb2JybyEhIQ0KKiAgIGF1dGxhamVyaSAtIG5hcmF2bm8gaW1hIGloDQoqICAgbm9ybWFsbm9zdCAtIG1hIGRhLCBhbGkgYmFyIGxpY2kgbmEgbmVzdG8gbm9ybWFsbm8uLi4NCg0KIyMjI1JhY2lvIHBva3JpY2Egb2JydG5lIGltb3ZpbmUgIA0KX19fX19fX19fX19fX18NCmBgYHtyLGZpZy53aWR0aD0xOCxmaWcuaGVpZ2h0PTN9DQojZGVmaW5pc2VtIGZ1bmtjaWp1IHphIHBsb3RvdmFuamUNCg0KcGxvdGluZyhscmdlLnRyYWluaW5nLDE4LDcpDQoNCmBgYA0KDQoqICAgUmFkbmEgaGlwb3RlemEtemFkb3ZvbGplbmEsIHZlY2kgZGlmb2x0IGtvZCBtYW5qaWggdnJlZG5vc3RpDQoqICAgRGlza3JpbWluYXRpdm5vc3QgLSBpbWEgbmEgOTUlIHpuYWNham5vc3RpICBpIG9rIGplLCBzb2xpZG5vISEhDQoqICAgYXV0bGFqZXJpIC0gbmFyYXZubyBpbWEgaWgNCiogICBub3JtYWxub3N0IC0gbWEgZGEgDQoNCiMjIyNSYWNpbyBvYnJ0YSBwb3RyYXppdmFuamEgb2Qga3VwYWNhICANCl9fX19fX19fX19fX19fX18NCmBgYHtyLGZpZy53aWR0aD0xOCxmaWcuaGVpZ2h0PTN9DQojZGVmaW5pc2VtIGZ1bmtjaWp1IHphIHBsb3RvdmFuamUNCg0KcGxvdGluZyhscmdlLnRyYWluaW5nLDE5LDcpDQoNCmBgYA0KDQoqICAgUmFkbmEgaGlwb3RlemEtemFkb3ZvbGplbmEsIHZlY2kgZGlmb2x0IGtvZCBtYW5qaWggdnJlZG5vc3RpDQoqICAgRGlza3JpbWluYXRpdm5vc3QgLSBuZW1hIGplIDk1JSB6bmFjYWpub3N0aQ0KKiAgIGF1dGxhamVyaSAtIG5hcmF2bm8gaW1hIGloDQoqICAgbm9ybWFsbm9zdCAtIG1hIGRhLCB2aXNlIGthbyAkXHRpbGRlXGNoaV4yJG5vc3QgaGloaWhpLCBrYXBpcmFzIGhpIGthbyBoaSBkaXN0cmlidWNpamEgOikgLi4uIA0KDQojIyMjUmFjaW8gb2JydGEgcG9zbG92bmUgaW1vdmluZSAgDQpfX19fX19fX19fX19fX19fX19fDQpgYGB7cixmaWcud2lkdGg9MTgsZmlnLmhlaWdodD0zfQ0KI2RlZmluaXNlbSBmdW5rY2lqdSB6YSBwbG90b3ZhbmplDQoNCnBsb3RpbmcobHJnZS50cmFpbmluZywyMCw3KQ0KDQpgYGANCiogICBSYWRuYSBoaXBvdGV6YS16YWRvdm9samVuYSwgdmVjaSBkaWZvbHQga29kIG1hbmppaCB2cmVkbm9zdGkNCiogICBEaXNrcmltaW5hdGl2bm9zdCAtIGltYSBuYSA5NSUgem5hY2Fqbm9zdGkgIGkgb2sgamUsIG1vemUgZGEgcHJvZGplLCBtYWRhIGtyaXZ1ZGEgc3RvIG5pamUgZG9icm8hISENCiogICBhdXRsYWplcmkgLSBuYXJhdm5vIGltYSBpaA0KKiAgIG5vcm1hbG5vc3QgLSBtYSBkYS4uLg0KDQojIyMjR290b3ZpbnNraSBjaWtsdXMgMSAgDQpfX19fX19fX19fX19fX19fX19fX19fDQpgYGB7cixmaWcud2lkdGg9MTgsZmlnLmhlaWdodD0zfQ0KI2RlZmluaXNlbSBmdW5rY2lqdSB6YSBwbG90b3ZhbmplDQoNCnBsb3RpbmcobHJnZS50cmFpbmluZywyMSw3KQ0KDQpgYGANCiogICBSYWRuYSBoaXBvdGV6YS1uZXphZG92b2xqZW5hLCB2ZWNpIGRpZm9sdCBrb2QgbWFuamloIHZyZWRub3N0aSwgemFzdG8gcGl0YW0gc2UNCiogICBEaXNrcmltaW5hdGl2bm9zdCAtIGltYSBuYSA5NSUgem5hY2Fqbm9zdGkgIGkgb2sgamUsIG1vemUgZGEgcHJvZGplLCBtYWRhIGtyaXZ1ZGEgc3RvIG5pamUgZG9icm8hISENCiogICBhdXRsYWplcmkgLSBuYXJhdm5vIGltYSBpaA0KKiAgIG5vcm1hbG5vc3QgLSBtYSBkYS4uLg0KDQojIyMjVnJlbWUgdmV6aXZhbmphIHphbGloYSAgDQpfX19fX19fX19fX19fX19fX19fX19fXw0KYGBge3IsZmlnLndpZHRoPTE4LGZpZy5oZWlnaHQ9M30NCiNkZWZpbmlzZW0gZnVua2NpanUgemEgcGxvdG92YW5qZQ0KDQpwbG90aW5nKGxyZ2UudHJhaW5pbmcsMjIsNykNCg0KYGBgDQoqICAgUmFkbmEgaGlwb3RlemEtemFkb3ZvbGplbmEsIHZlY2kgZGlmb2x0IGtvZCB2ZWNpaCB2cmVkbm9zdGkNCiogICBEaXNrcmltaW5hdGl2bm9zdCAtIG5lbWEgbmEgOTUlIHpuYWNham5vc3RpDQoqICAgYXV0bGFqZXJpIC0gbmFyYXZubyBpbWEgaWgNCiogICBub3JtYWxub3N0IC0gbWEgZGEuLi4NCg0KIyMjI1ZyZW1lIGtyZWRpdGlyYW5qYSBrdXBhY2EgIA0KX19fX19fX19fX19fX19fX19fX19fX19fX19fX18NCmBgYHtyLGZpZy53aWR0aD0xOCxmaWcuaGVpZ2h0PTN9DQojZGVmaW5pc2VtIGZ1bmtjaWp1IHphIHBsb3RvdmFuamUNCg0KcGxvdGluZyhscmdlLnRyYWluaW5nLDIzLDcpDQoNCmBgYA0KKiAgIFJhZG5hIGhpcG90ZXphLXphZG92b2xqZW5hLCB2ZWNpIGRpZm9sdCBrb2QgdmVjaWggdnJlZG5vc3RpDQoqICAgRGlza3JpbWluYXRpdm5vc3QgLSBuZW1hIG5hIDk1JSB6bmFjYWpub3N0aQ0KKiAgIGF1dGxhamVyaSAtIG5hcmF2bm8gaW1hIGloDQoqICAgbm9ybWFsbm9zdCAtIG1hIGRhLi4uDQoNCiMjIyNWcmVtZSBuYXBsYXRlIHBvdHJhxb5pdmFuamEgIA0KX19fX19fX19fX19fX19fX19fDQpgYGB7cixmaWcud2lkdGg9MTgsZmlnLmhlaWdodD0zfQ0KI2RlZmluaXNlbSBmdW5rY2lqdSB6YSBwbG90b3ZhbmplDQoNCnBsb3RpbmcobHJnZS50cmFpbmluZywyNCw3KQ0KDQpgYGANCiogICBSYWRuYSBoaXBvdGV6YS16YWRvdm9samVuYSwgdmVjaSBkaWZvbHQga29kIHZlY2loIHZyZWRub3N0aQ0KKiAgIERpc2tyaW1pbmF0aXZub3N0IC0gaW1hIG5hIDk1JSB6bmFjYWpub3N0aQ0KKiAgIGF1dGxhamVyaSAtIG5hcmF2bm8gaW1hIGloDQoqICAgbm9ybWFsbm9zdCAtIG1hIGRhLi4uDQoNCiMjIyNWcmVtZSBwbGHEh2FuamEgZG9iYXZsamHEjWltYSAgDQpfX19fX19fX19fX19fX18NCmBgYHtyLGZpZy53aWR0aD0xOCxmaWcuaGVpZ2h0PTN9DQojZGVmaW5pc2VtIGZ1bmtjaWp1IHphIHBsb3RvdmFuamUNCg0KcGxvdGluZyhscmdlLnRyYWluaW5nLDI1LDcpDQoNCmBgYA0KDQoqICAgUmFkbmEgaGlwb3RlemEtbmV6YWRvdm9samVuYSwgdmVjaSBkaWZvbHQga29kIG1hbmppaCB2cmVkbm9zdGksIGlwYWsgY2VtbyBqZSB1emV0aSwgamVyIG1vxb5lIGVrb25vbXNraSBkYSBzZSBvYmphc25pIHJlenVsdGF0DQoqICAgRGlza3JpbWluYXRpdm5vc3QgLSBpbWEgbmEgOTUlIHpuYWNham5vc3RpIHN1cHJvdGFuIHpuYWssIG9ubyBzdG8gYmkgbW9nbG8gcHJhdml0aSBwcm9ibGVtIGplIHByb21lbmEgZGlza3JpbWluYXRpdm5vc3RpIGtvZCBwb3NsZWRuamUgY2V0dnJ0aW5lIGRpc3RyaWJ1Y2lqZQ0KKiAgIGF1dGxhamVyaSAtIG5hcmF2bm8gaW1hIGloDQoqICAgbm9ybWFsbm9zdCAtIG1hIGRhLi4uDQoNCiMjIyNBc3NldCB0dXJub3Zlcg0KX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18NCmBgYHtyLGZpZy53aWR0aD0xOCxmaWcuaGVpZ2h0PTN9DQojZGVmaW5pc2VtIGZ1bmtjaWp1IHphIHBsb3RvdmFuamUNCg0KcGxvdGluZyhscmdlLnRyYWluaW5nLDI2LDcpDQoNCmBgYA0KDQoqICAgUmFkbmEgaGlwb3RlemEtemFkb3ZvbGplbmEsIHZlY2EgdmVyb3ZhdG5vY2EgZGlmb2x0YSBrb2QgbWFuamUgbWVkaWphbmUNCiogICBEaXNrcmltaW5hdGl2bm9zdCAtIG5lbWEgbmEgOTUlIHpuYWNham5vc3RpLCBpcGFrIGNlbW8gamUgdXpldGksIHpib2cgZGlza3JpbWluYXRpdm5vc3RpIHUgbWFuamltIHZyZWRub3N0aW1hDQoqICAgYXV0bGFqZXJpIC0gbmFyYXZubyBpbWEgaWgNCiogICBub3JtYWxub3N0IC0gbWEgZGEuLi4NCg0KDQojIyMjUmFzdCBFQklUREENCl9fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fDQpgYGB7cixmaWcud2lkdGg9MTgsZmlnLmhlaWdodD0zfQ0KI2RlZmluaXNlbSBmdW5rY2lqdSB6YSBwbG90b3ZhbmplDQoNCnBsb3RpbmcobHJnZS50cmFpbmluZywyNyw3KQ0KDQpgYGANCiogICBSYWRuYSBoaXBvdGV6YS16YWRvdm9samVuYSwgdmVjYSB2ZXJvdmF0bm9jYSBkaWZvbHRhIGtvZCBtYW5qZSBtZWRpamFuZQ0KKiAgIERpc2tyaW1pbmF0aXZub3N0IC0gbmEgZ3JhbmljaSBuYSA5NSUgem5hY2Fqbm9zdGksIHV6ZWNlbW8sIG1hZGEgbWVuamEgZGlza3JpbWluYXRpdm5vc3QsIHZpZGVjZW1vIHBvc2xlIG11bHRpdmFyaWF0YQ0KKiAgIGF1dGxhamVyaSAtIG5hcmF2bm8gaW1hIGloDQoqICAgbm9ybWFsbm9zdCAtIG1hIGRhLi4uDQoNCiMjIyNTdG9wYSBwcmlub3NhIG5hIHNvcHN0dmVuaSBrYXBpdGFsIHByZSBvcG9yZXppdmFuamENCl9fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fDQpgYGB7cixmaWcud2lkdGg9MTgsZmlnLmhlaWdodD0zfQ0KI2RlZmluaXNlbSBmdW5rY2lqdSB6YSBwbG90b3ZhbmplDQoNCnBsb3RpbmcobHJnZS50cmFpbmluZywyOCw3KQ0KDQpgYGANCg0KKiAgIFJhZG5hIGhpcG90ZXphLW5lIHpuYW0ga29qaSBtdSBqZSBkamF2byBhbGkgZXZvIG92ZGUgY2VtbyBtZWRpamFuYSB6ZHJhdm9nIGplIGByIG1lZGlhbihhcy5tYXRyaXgobHJnZS50cmFpbmluZ1tkZWZhdWx0Lnk9PTAsMjhdKSxuYS5ybT1UKWAgYSBuZXNvbHZlbnRub2cgamUgYHIgbWVkaWFuKGFzLm1hdHJpeChscmdlLnRyYWluaW5nW2RlZmF1bHQueT09MSwyOF0pLG5hLnJtPVQpYCBzdG8gb2Rnb3ZhcmEgcmFkbm9qIGhpcG90ZXppDQoqICAgRGlza3JpbWluYXRpdm5vc3QgLSB6bmFjYWpubyBuYSA5NSUgem5hY2Fqbm9zdGksIHV6ZWNlbW8NCiogICBhdXRsYWplcmkgLSBuYXJhdm5vIGltYSBpaA0KKiAgIG5vcm1hbG5vc3QgLSBtYSBkYS4uLg0KDQojIyMjU3RvcGEgcHJpbm9zYSBuYSB1a3VwbmEgc3JlZHN0dmEgcHJlIG9wb3Jleml2YW5qYQ0KX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18NCmBgYHtyLGZpZy53aWR0aD0xOCxmaWcuaGVpZ2h0PTN9DQojZGVmaW5pc2VtIGZ1bmtjaWp1IHphIHBsb3RvdmFuamUNCg0KcGxvdGluZyhscmdlLnRyYWluaW5nLDI5LDcpDQoNCmBgYA0KDQoqICAgUmFkbmEgaGlwb3RlemEtbmUgem5hbSBrb2ppIG11IGplIGRqYXZvIGFsaSBldm8gb3ZkZSBjZW1vIG1lZGlqYW5hIHpkcmF2b2cgamUgYHIgbWVkaWFuKGFzLm1hdHJpeChscmdlLnRyYWluaW5nW2RlZmF1bHQueT09MCwyOV0pLG5hLnJtPVQpYCBhIG5lc29sdmVudG5vZyBqZSBgciBtZWRpYW4oYXMubWF0cml4KGxyZ2UudHJhaW5pbmdbZGVmYXVsdC55PT0xLDI5XSksbmEucm09VClgIHN0byBvZGdvdmFyYSByYWRub2ogaGlwb3RlemkNCiogICBEaXNrcmltaW5hdGl2bm9zdCAtIHpuYWNham5vIG5hIDk1JSB6bmFjYWpub3N0aSwgbXVhDQoqICAgYXV0bGFqZXJpIC0gbmFyYXZubyBpbWEgaWgNCiogICBub3JtYWxub3N0IC0gamVkYW4gb2QgYmxpemloLi4uDQoNCiMjIyNCYXNpYyBFYXJuaW5ncyBQb3dlciBSYXRpbw0KX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18NCmBgYHtyLGZpZy53aWR0aD0xOCxmaWcuaGVpZ2h0PTN9DQojZGVmaW5pc2VtIGZ1bmtjaWp1IHphIHBsb3RvdmFuamUNCg0KcGxvdGluZyhscmdlLnRyYWluaW5nLDMwLDcpDQoNCmBgYA0KDQoqICAgUmFkbmEgaGlwb3RlemEtemFkb3ZvbGplbmEgamUsIHZlY2kgZGlmb2x0IHNhIG1hbmpvbSB2cmVkbm9zY3UNCiogICBEaXNrcmltaW5hdGl2bm9zdCAtIGltYSBuYSA5NSUgem5hY2Fqbm9zdGksIG11YQ0KKiAgIGF1dGxhamVyaSAtIG5hcmF2bm8gaW1hIGloDQoqICAgbm9ybWFsbm9zdCAtIGpvb2suLi4NCg0KIyMjI1Jhc3QgcHJpaG9kYSBvZCBwcm9kYWplDQpfX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fXw0KYGBge3IsZmlnLndpZHRoPTE4LGZpZy5oZWlnaHQ9M30NCiNkZWZpbmlzZW0gZnVua2NpanUgemEgcGxvdG92YW5qZQ0KDQpwbG90aW5nKGxyZ2UudHJhaW5pbmcsMzEsNykNCg0KYGBgDQoNCiogICBSYWRuYSBoaXBvdGV6YS1uZXphZG92b2xqZW5hIGplLCBuZW1hIHZpZGxqaXZlIHJhemxpa2UNCiogICBEaXNrcmltaW5hdGl2bm9zdCAtIG5pamUgem5hY2FqbmEgbmEgOTUlIHpuYWNham5vc3RpLCBrYW5kaWRhdCB6YSBrYXRlZ29yaWNrdQ0KKiAgIGF1dGxhamVyaSAtIG5hcmF2bm8gaW1hIGloDQoqICAgbm9ybWFsbm9zdCAtIGpvb2suLi4NCg0KIyMjI1Bva3JpxIdlIG5ldG8ga2FtYXRhDQpfX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fXw0KYGBge3IsZmlnLndpZHRoPTE4LGZpZy5oZWlnaHQ9M30NCiNkZWZpbmlzZW0gZnVua2NpanUgemEgcGxvdG92YW5qZQ0KDQpwbG90aW5nKGxyZ2UudHJhaW5pbmcsMzIsNykNCg0KYGBgDQoqICAgUmFkbmEgaGlwb3RlemEtemFkb3ZvbGplbmEgamUgbWFkYSBuZW1hIHZpZGxqaXZlIHJhemxpa2UgemJvZyBhdXRsYWplcmENCiogICBEaXNrcmltaW5hdGl2bm9zdCAtIG5pamUgem5hY2FqbmEgbmEgOTUlIHpuYWNham5vc3RpLCBtZWRqdXRpbSBST0MgaW1hIHMgb2JsaWsgc3RvIHpuYWNpIGRhIHBvc3RvamkgZGlza3JpbWluYXRpdm5vc3Qgb2JybnV0b2cgc21lcmEgbmEgdmVjaW0gaSBtYW5qaW0gdnJlZG5vc3RpbWEsIG1lZGp1dGltIG92byB6bmFjaSBpIGRhIG9kbm9zIHNhIHZlcm92YXRub2NvbSBkZWZhdWx0LWEgbmlqZSBtb25vdG9uLCBrYW5kaWRhdCB6YSBrYXRlZ29yaWNrdQ0KKiAgIGF1dGxhamVyaSAtIG5hcmF2bm8gaW1hIGloDQoqICAgbm9ybWFsbm9zdCAtIGpvb2suLi4NCg0KIyMjI0NlbmEgdHXEkWloIGl6dm9yYSBzcmVkc3RhdmENCl9fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fDQpgYGB7cixmaWcud2lkdGg9MTgsZmlnLmhlaWdodD0zfQ0KI2RlZmluaXNlbSBmdW5rY2lqdSB6YSBwbG90b3ZhbmplDQoNCnBsb3RpbmcobHJnZS50cmFpbmluZywzMyw3KQ0KDQpgYGANCiogICBSYWRuYSBoaXBvdGV6YS16YWRvdm9samVuYSBqZSwgbmVtYSB2aWRsaml2ZSByYXpsaWtlDQoqICAgRGlza3JpbWluYXRpdm5vc3QgLSBuaWplIHpuYWNham5hIG5hIDk1JSB6bmFjYWpub3N0aSwgbWVkanV0aW0gUk9DIGltYSBzIG9ibGlrIHN0byB6bmFjaSBkYSBwb3N0b2ppIGRpc2tyaW1pbmF0aXZub3N0IG9icm51dG9nIHNtZXJhIG5hIHZlY2ltIGkgbWFuamltIHZyZWRub3N0aW1hLCBtZWRqdXRpbSBvdm8gem5hY2kgaSBkYSBvZG5vcyBzYSB2ZXJvdmF0bm9jb20gZGVmYXVsdC1hIG5pamUgbW9ub3Rvbg0KKiAgIGF1dGxhamVyaSAtIG5hcmF2bm8gaW1hIGloDQoqICAgbm9ybWFsbm9zdCAtIGpvb2suLi4NCg0KDQojIyMjVDENCl9fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fDQpgYGB7cixmaWcud2lkdGg9MTgsZmlnLmhlaWdodD0zfQ0KI2RlZmluaXNlbSBmdW5rY2lqdSB6YSBwbG90b3ZhbmplDQoNCnBsb3RpbmcobHJnZS50cmFpbmluZywzNCw3KQ0KDQpgYGANCiogICBSYWRuYSBoaXBvdGV6YS16YWRvdm9samVuYSBqZQ0KKiAgIERpc2tyaW1pbmF0aXZub3N0IC0gem5hY2FqbmEgbmEgOTUlIHpuYWNham5vc3RpLCBtZWRqdXRpbSBicmluZSBtb25vdG9ub3N0LCBtb3plIGRhIHByb2RqZQ0KKiAgIGF1dGxhamVyaSAtIG5hcmF2bm8gaW1hIGloDQoqICAgbm9ybWFsbm9zdCAtIGpvb2suLi4NCg0KIyMjI1QyDQpfX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fXw0KYGBge3IsZmlnLndpZHRoPTE4LGZpZy5oZWlnaHQ9M30NCiNkZWZpbmlzZW0gZnVua2NpanUgemEgcGxvdG92YW5qZQ0KDQpwbG90aW5nKGxyZ2UudHJhaW5pbmcsMzUsNykNCg0KYGBgDQoNCiogICBSYWRuYSBoaXBvdGV6YS16YWRvdm9samVuYSBqZQ0KKiAgIERpc2tyaW1pbmF0aXZub3N0IC0gem5hY2FqbmEgbmEgOTUlIHpuYWNham5vc3RpDQoqICAgYXV0bGFqZXJpIC0gbmFyYXZubyBpbWEgaWgNCiogICBub3JtYWxub3N0IC0gam9vay4uLg0KDQojIyMjVDMNCl9fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fDQpgYGB7cixmaWcud2lkdGg9MTgsZmlnLmhlaWdodD0zfQ0KI2RlZmluaXNlbSBmdW5rY2lqdSB6YSBwbG90b3ZhbmplDQoNCnBsb3RpbmcobHJnZS50cmFpbmluZywzNiw3KQ0KDQpgYGANCg0KKiAgIFJhZG5hIGhpcG90ZXphLXphZG92b2xqZW5hIGplDQoqICAgRGlza3JpbWluYXRpdm5vc3QgLSB6bmFjYWpuYSBuYSA5NSUgem5hY2Fqbm9zdGkNCiogICBhdXRsYWplcmkgLSBuYXJhdm5vIGltYSBpaA0KKiAgIG5vcm1hbG5vc3QgLSBqb29rLi4uDQoNCg0KIyMjI1Q0DQpfX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fXw0KYGBge3IsZmlnLndpZHRoPTE4LGZpZy5oZWlnaHQ9M30NCiNkZWZpbmlzZW0gZnVua2NpanUgemEgcGxvdG92YW5qZQ0KDQpwbG90aW5nKGxyZ2UudHJhaW5pbmcsMzcsNykNCg0KYGBgDQoNCg0KKiAgIFJhZG5hIGhpcG90ZXphLXphZG92b2xqZW5hIGplDQoqICAgRGlza3JpbWluYXRpdm5vc3QgLSBtYXN0ZXJwaWVjZQ0KKiAgIGF1dGxhamVyaSAtIG5hcmF2bm8gaW1hIGloDQoqICAgbm9ybWFsbm9zdCAtIGpvb2suLi4NCg0KIyMjI1Q1DQpfX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fXw0KYGBge3IsZmlnLndpZHRoPTE4LGZpZy5oZWlnaHQ9M30NCiNkZWZpbmlzZW0gZnVua2NpanUgemEgcGxvdG92YW5qZQ0KDQpwbG90aW5nKGxyZ2UudHJhaW5pbmcsMzgsNykNCg0KYGBgDQoNCiogICBSYWRuYSBoaXBvdGV6YS16YWRvdm9samVuYSBqZQ0KKiAgIERpc2tyaW1pbmF0aXZub3N0IC0gbmVtYQ0KKiAgIGF1dGxhamVyaSAtIG5hcmF2bm8gaW1hIGloDQoqICAgbm9ybWFsbm9zdCAtIGpvb2suLi4NCg0KIyMjI1QyMQ0KX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18NCmBgYHtyLGZpZy53aWR0aD0xOCxmaWcuaGVpZ2h0PTN9DQojZGVmaW5pc2VtIGZ1bmtjaWp1IHphIHBsb3RvdmFuamUNCg0KcGxvdGluZyhscmdlLnRyYWluaW5nLDM5LDcpDQoNCmBgYA0KDQoNCiogICBSYWRuYSBoaXBvdGV6YS1uZXphZG92b2xqZW5hDQoqICAgRGlza3JpbWluYXRpdm5vc3QgLSBuZW1hLCB6YSBtYWxvDQoqICAgYXV0bGFqZXJpIC0gbmFyYXZubyBpbWEgaWgNCiogICBub3JtYWxub3N0IC0gam9vay4uLg0KDQojIyMjQWx0bWFuIFotc2NvcmUgMQ0KX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18NCmBgYHtyLGZpZy53aWR0aD0xOCxmaWcuaGVpZ2h0PTN9DQojZGVmaW5pc2VtIGZ1bmtjaWp1IHphIHBsb3RvdmFuamUNCg0KcGxvdGluZyhscmdlLnRyYWluaW5nLDQwLDcpDQoNCmBgYA0KDQoqICAgUmFkbmEgaGlwb3RlemEtemFkb3ZvbGplbmEgamUNCiogICBEaXNrcmltaW5hdGl2bm9zdCAtIG1hc3RlcnBpZWNlDQoqICAgYXV0bGFqZXJpIC0gbmFyYXZubyBpbWEgaWgNCiogICBub3JtYWxub3N0IC0gam9vay4uLiAgDQoNCiMjIyNBbHRtYW4gWi1zY29yZSAyDQpfX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fXw0KYGBge3IsZmlnLndpZHRoPTE4LGZpZy5oZWlnaHQ9M30NCiNkZWZpbmlzZW0gZnVua2NpanUgemEgcGxvdG92YW5qZQ0KDQpwbG90aW5nKGxyZ2UudHJhaW5pbmcsNDEsNykNCg0KYGBgDQoqICAgUmFkbmEgaGlwb3RlemEtemFkb3ZvbGplbmEgamUNCiogICBEaXNrcmltaW5hdGl2bm9zdCAtIG1hc3RlcnBpZWNlDQoqICAgYXV0bGFqZXJpIC0gbmFyYXZubyBpbWEgaWgNCiogICBub3JtYWxub3N0IC0gam9vay4uLiAgDQoNCiMjIyNBbHRtYW4gWi1zY29yZSAzDQpfX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fXw0KYGBge3IsZmlnLndpZHRoPTE4LGZpZy5oZWlnaHQ9M30NCiNkZWZpbmlzZW0gZnVua2NpanUgemEgcGxvdG92YW5qZQ0KDQpwbG90aW5nKGxyZ2UudHJhaW5pbmcsNDIsNykNCg0KYGBgDQoqICAgUmFkbmEgaGlwb3RlemEtemFkb3ZvbGplbmEgamUNCiogICBEaXNrcmltaW5hdGl2bm9zdCAtIG1hc3RlcnBpZWNlDQoqICAgYXV0bGFqZXJpIC0gbmFyYXZubyBpbWEgaWgNCiogICBub3JtYWxub3N0IC0gam9vay4uLiAgDQoNCg0KIyMjI1VkZW8gdSBrYXBpdGFsdSBiYW5rZQ0KX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18NCmBgYHtyLGZpZy53aWR0aD0xOCxmaWcuaGVpZ2h0PTN9DQojZGVmaW5pc2VtIGZ1bmtjaWp1IHphIHBsb3RvdmFuamUNCg0KcGxvdGluZyhscmdlLnRyYWluaW5nLDQzLDcpDQoNCmBgYA0KDQoqICAgUmFkbmEgaGlwb3RlemEtemFkb3ZvbGplbmEgamUsIHZlY2kgdWRlbyBsb3Npamkgc3UgdSBwcm9zZWt1DQoqICAgRGlza3JpbWluYXRpdm5vc3QgLSB6YSB2ZWNlIHZyZWRub3N0aSBkYQ0KKiAgIGF1dGxhamVyaSAtIG5hcmF2bm8gaW1hIGloDQoqICAgbm9ybWFsbm9zdCAtIGpvb2suLi4gIA0KDQpfX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fDQoNCg0KIyMjS29yZWxhY2lvbmEgbWF0cmljYSAgDQoNCkthbyBkb2RhdG5pIGtyaXRlcmlqdW0gc2VsZWtjaWplIHV6aW1hbW8gaSBrb3JlbGFjaW9udSBtYXRyaWN1LiBWb2RpY2VtbyBzZSBwcmUgc3ZlZ2EgZGlza3JpbWluYXRpdm5vbSBtb2NpIGtvanUgcG9zbWF0cmFtbyBwcmVtYSBBVVJPQyB2cmVkbm9zdGkga2FvIHBydmltIGtyaXRlcmlqdW1vbSBwcmkgaXpib3J1IGl6bWVkanUgZHZlIHZhcmlqYWJsZSBzYSB2ZWxpa2ltIHN0ZXBlbm9tIGtvcmVsYWNpamUuICANClUgdGFiZWxpIDUuIGlzcG9kIHZpZGltbyBkYSBuYWp2ZWN1IGRpc2tyaW1pbmFjaW9udSBtb2MgcG9zZWR1amUgdmFyaWphYmxhIFQxNCBvZG1haCBpemEga29qZSBqZSBBTHRtYW4gMS4gDQpgYGB7ciwgbWVzc2FnZT1GLCB3YXJuaW5nPUZ9DQojcHJvcmFjdW4NCmNvcj1jb3IobHJnZS50cmFpbmluZy5jb250aW51YWxuZVssYygtMSwtMzEsLTMyLC0zMyldLCB1c2UgPSAiY29tcGxldGUub2JzIikNCg0KI2RvZGFqZW1vIEFVUk9DIGthbyBkb2RhdG51IGtvbG9udSBwb3JlZCB2YXJpamFibGUNCg0KY29ycl9zdW1tYXJ5PC1mdW5jdGlvbiAocHJlZGljdG9yKXsNCiAgcmVzcG9uc2U9ZmFjdG9yKGxyZ2UudHJhaW5pbmcuY29udGludWFsbmVbWzFdXSkNCnN1cHByZXNzTWVzc2FnZXMoYXVjKHJlc3BvbnNlLCBhcy5udW1lcmljKHByZWRpY3RvcikpKQ0KfQ0KDQphdWNfc3VtYXJubzwtc2FwcGx5KGxyZ2UudHJhaW5pbmcuY29udGludWFsbmVbLGMoLTEsLTMxLC0zMiwtMzMpXSwgY29ycl9zdW1tYXJ5KQ0Ka29yX2Rpc2tyPC0oY2JpbmQoYXVjX3N1bWFybm8sY29yKSkgDQoNCmZvcm1hdFJvdW5kKA0KICAgICAgICAgICAgZGF0YXRhYmxlKA0KICAgICAgICAgICAgICAgICAgICAgIGtvcl9kaXNrcixjYXB0aW9uID0gIlRhYmVsYSA1LjpTdW1hcm5pIHByaWtheiIsDQogICAgICAgICAgICAgICAgICAgICAgZmlsdGVyID0gJ25vbmUnDQogICAgICAgICAgICAgICAgICAgICAgKSwNCiAgICAgICAgICAgIGNvbHVtbnMgPSBjb2xuYW1lcyhrb3JfZGlza3IpDQogICAgICAgICAgICkNCg0KYGBgDQoNCk92ZGUga3JlaXJhbSBmdW5rY2lqdSBrb2phIGNlIGRhIGZpbHRyaXJhIHZhcmlqYWJsZSBwbyBrcml0ZXJpanVtdSBrb3JlbGFjaWplLiBOYWltZSwgcG8gdWdsZWR1IG5hIFteNF0ga2FvIGtyaXRlcmlqdW0gZ3JhbmljZSBrb2VmaWNpamVudGEga29yZWxhY2lqZSBwcmVrbyBrb2plIG5lIGJpc21vIHNtZWxpIHByZWxheml0aSB1emVjZW1vIHZyZWRub3N0IG9kIDAuNSBrb2ppIGNlIHUgc3ByZXppIHNhIEFVUk9DIHZyZWRub3N0aSBzZWxla3RpcmF0aSBqZWRudSBvZCBkdmUgdmFyaWphYmxlLiBLb25hY2FuIGl6Ym9yIHZhcmlqYWJsaSBzZSB2aWRpIHUga29yZWxhY2lvbm9qIHRhYmVsaSBpc3BvZC4gIA0KDQpgYGB7cn0NCiNhc3N1bWluZyB0aGF0IHRhYmxlIGlzIG4geCAobisxKSBtYXRyaXggd2hlcmUgZmlyc3QgY29sdW1uIGlzIEFVUk9DIHZhbHVlIGFuZCB0aGUgcmVzdCBuIHggbiBpcyBjb3JyZWxhdGlvbiBtYXRyaXggDQpjb3JyX2VsbGltaW5hdGlvbjwtZnVuY3Rpb24odGFibGUxLCBybz0wLjUpew0KICB0YWJsZT10YWJsZTENCiAgQVVST0M8LXRhYmxlWywxXQ0KICB0YWJsZTwtdGFibGVbb3JkZXIodGFibGVbLDFdLGRlY3JlYXNpbmcgPSBUKSxdWywtMV0NCiAgdGFibGUudGVtcD1hcy5kYXRhLmZyYW1lKHRhYmxlKQ0KICBmb3IoaSBpbiAxOm5jb2wodGFibGUpKXsja29sb25hDQogICAgZm9yKGogaW4gMTpucm93KHRhYmxlKSl7I3JlZA0KICAgICAgI2Jyb3dzZXIoKQ0KICAgICAgaWYoYWJzKHRhYmxlW2ksal0pPnJvICYgYWJzKHRhYmxlW2ksal0pPDEpew0KICAgICAgICByb3cubmFtZT1yb3duYW1lcyh0YWJsZSlbaV0NCiAgICAgICAgaWYoc3VtKHJvdy5uYW1lPT1jb2xuYW1lcyh0YWJsZS50ZW1wKSk9PTApIG5leHQNCiAgICAgICAgY29sLm5hbWU9Y29sbmFtZXModGFibGUpW2pdDQogICAgICAgIHRhYmxlLnRlbXA9dGFibGUudGVtcFssY29sLm5hbWUhPWNvbG5hbWVzKHRhYmxlLnRlbXApXQ0KICAgICAgICB0YWJsZS50ZW1wPXRhYmxlLnRlbXBbY29sLm5hbWUhPXJvdy5uYW1lcyh0YWJsZS50ZW1wKSxdDQogICAgICB9DQogICAgfQ0KICB9DQogIA0KICBBVVJPQz1BVVJPQ1tyb3duYW1lcyh0YWJsZS50ZW1wKV0NCiAgDQogIHRhYmxlLnRlbXA9Y2JpbmQoQVVST0MsdGFibGUudGVtcCkNCiAgdGFibGUudGVtcDwtdGFibGUudGVtcFtBVVJPQz4wLjU1LF0NCiAgdGFibGUudGVtcDwtdGFibGUudGVtcFsscm93bmFtZXModGFibGUudGVtcCldDQogIA0KICB0YWJsZS50ZW1wW29yZGVyKHJvd25hbWVzKHRhYmxlLnRlbXApKSxvcmRlcihjb2xuYW1lcyh0YWJsZS50ZW1wKSldDQogIEFVUk9DPUFVUk9DW3Jvd25hbWVzKHRhYmxlLnRlbXApXQ0KICB0YWJsZS50ZW1wPWNiaW5kKEFVUk9DLHRhYmxlLnRlbXApDQoNCn0NCg0KY2xlYW5fY29yPC1jb3JyX2VsbGltaW5hdGlvbihrb3JfZGlza3IpDQprbml0cjo6a2FibGUoY2xlYW5fY29yLCBjYXB0aW9uID0gIlRhYmVsYSA2LiBza3JhY2VuYSBrb3JlbGFjaW9uYSB0YWJlbGEga29qYSBzYWRyemkgdmFyaWphYmxlIG5hZCBrb2ppbWEgY2Ugc2UgdnJzaXRpIGRhbGphIGFuYWxpemEiKQ0KDQpgYGANCg0KRGEgc3VtaXJhbW8sIGRvIHNhZGEgc21vIGtvZCBrb250aW51YWxuaWgsIHByZWdsZWRhbGkgZGlza3JpbWluYXRpdm5vc3QuIEdlbmVyYWxubyBbXjRdIHByZXBvcnVjdWplIGRhIHNlIG9kcmFkaSAqdW5pdmFyaWF0ZSogbG9naXN0aWNrYSBwYSBuamVuYSBkaXNrcmltaW5hdGl2bm9zdCB0ZXN0aXJhLiBNZWRqdXRpbSBvdmRlIHNtbyBwcmF0aWxpIFteNV0gZ2RlIHNtbyBwb3NtYXRyYWxpIGRpc2tyaW1pbmF0aXZub3N0IHNhbWloIHZhcmlqYWJsaS4gRGFsamUsIHBvc3RvamkgcGFyIHZhcmlqYWJsaSBrb2plIGJpc21vIG1vZ2xpIGRhIHRyYW5zZm9ybWlzZW1vIHUga2F0ZWdvcmlja2UsIHN0byBqZSBwb3plbGpuby4gIA0KDQpPc2ltIHRlc3RpcmFuamEgbW9ub3Rvbm9zdGkgaGlwb3RlemUsIG5lZ2RlIHNlIHRlc3RpcmEgaSBwb3N0b2phbmplIGxpbmVhcm5lIHphdmlzbm9zdCBpem1lZGp1IGxvZ2FyaXRtYSBlbXBpcmlqc2tpaCBzYW5zaSBpIHZhcmlqYWJsaVteNF0gaSBpc3RvdnJlbWVubyBzZSB0cmFuc2Zvcm1pc3UgdmFyaWphYmxlLiBbXjZdIHByaWthenVqdSBwb3N0dXBhayB0cmFuc2Zvcm1hY2lqZSBhbGkgaSB1cG96b3JhdmFqdSBuYSBvcGFzbm9zdCBvZCAqZGF0YS5taW5pbmcqLWEsIFteNV0gaSBbXjRdIHRha29kamUgcHJpbWVuanVqdSBpc3RvdmV0YW4gcG9zdHVwYWsuIE1pIGNlbW8gb3ZkZSBrb3Jpc3RpdGkgcG9zdHVwYWsgb3Bpc2FuIHUgW142XSB6YSBwYXIgdmFyaWphYmxpIGtvamUgbmlzdSBwb2themFsZSBtb25vdG9udSB6YXZpc25vc3Qgc2EgaGlwb3Rlem9tLCB1a29saWtvIG51emRhIG5hdGVyYSwgYWxpIHNhbW8gdGFkYSwgdHJhbnNmb3JtaXNhY2VtbyBzdmUga29udGludWFsbmUgdmFyaWphYmxlLiBaYSBzYWRhIGNlbW8gb3ZhaiBwb3N0dXBhayBwcmltZW5pdGkgbmEgdmFyaWphYmxhbWEgKlBva3JpxIdlIG5ldG8ga2FtYXRhLCBBc3NldCB0dXJub3ZlciouIFZhcmlqYWJsYSBrb2p1IGNlbW8gcHJldHZvcml0aSB1IGthdGVnb3JpY2t1IGplICpVZGVvIHUga2FwaXRhbHUgYmFua2UqLiBEaW5hbWlja2UgdmFyaWphYmxlICpSYXN0IEVCSVREQSBpIFJhY2lvIG9icnRhIHBvc2xvdm5lIGltb3ZpbmUqIG5lbWFqdSBuZWt1IHByZXZpc2Ugem5hY2FqbnUgZGlza3JpbWluYXRpdm51IG1vYyBkYSBiaSBzZSBvcHJhdmRhbG8gc2tyYWNlbmplIGNpdGF2ZSBzZXJpamUgdXpvcmthLCB0YWtvIGRhIGNlIHNlIHRyZXRpcmF0aSBrYW8gZGEgc3Ugb3RwYWxlIHUgKnVuaXZhcmlhdGUgYW5hbHlzaXMqIHVzbGVkIHZlbGlrb2cgYnJvamEgbmVkb3N0YWp1Y2loIHZyZWRub3N0aS4gTmFwcmF2aWNlbW8gamVkYW4gaXp1emV0YWsga2FkYSBidWRlbW8gcHJpbWVuaWxpIHByYXZpbG8gb2RzdHJhbmppdmFuamEgdmFyaWphYmxpIHVzbGVkIG5lZG9zdGFqdWNpaCB2cmVkbm9zdGksIGEgdG8gamUgdmFyaWphYmxhIGtvamEgamUgbmEgZ3JhbmljaSwgKkNhc2hfcmF0aW8qIGplciBqZSBwb2themFsYSB2ZWxpa3UgZGlza3JpbWFjaW9udSBtb2MuIERpc2tyaW1pbmFjaW9udSBtb2MgZ2xlZGFtbyBwbyB6bmFjYWpub3N0aSBpbnRlcnZhbGEgcG92ZXJlbmphIG9kIDk1JSwga29qaSBzZSBrb2QgZnVua2NpamUgdSBSLXUgcmFjdW5hIGJvb3RzdHJhcG92YW5qZW0uIEdlbmVyYWxubywgdnJlZG5vc3RpIEFVUk9DLWEgdSB2ZWNpbSB1em9yY2ltYSBrb2plIGltYWp1IHZyZWRub3N0aSB2ZWNlIG9kIDU1IHNlIG1vZ3Ugc21hdHJhdGkgem5hY2FqbmltLiAgDQoNClBhIGhhamRlIGRhIGtyZW5lbW8gc2EgZ29yZSBuYXZlZGVuaW0uIFRha29kamUsIHZpZGVoIGRhIGplIG1vemRhIGJyb2ogemFwb3NsZW5paCBiaWxvIHBvdHJlYm5vIHJ0YWN1bmF0aSBwcmVtYSBha3Rpdmkga2FvIHJhY2lvLCBhbGkgdG8gbWkgIHJhbmlqZSBuaWplIHBhbG8gbmEgcGFtZXQsIG1hZGEgbmUgbWlzbGltIGRhIGJpIGltYWxvIHpuYWNham5paCBwcm9tZW5hLCBldmVudHVhbG5vLCB2YXJpamFibGEga29qYSBiaSBpbWFsYSBzbWlzbGEgamUgcHJvY2VudHVhbG5hIHByb21lbmEgb3ZlIHZhcmlqYWJsZSwgxaF0byBiaSwgb3BldCwgemFodGV2YWxvIGd1YmxqZW5qZSBwcnZlIGdvZGluZSBvYnNlcnZhY2lqYSBzYW1vIHpib2cgbmplLCBqZXIgc2UgZHJ1Z2UgZGluYW1pY2tlIHZhcmlqYWJsZSBuaXN1IHBva2F6YWxlIGthbyBkb3ZvbGpubyBkaXNrcmltaW5hdGl2bm8gem5hY2FqbmUuICANCg0KRG9kYXRubyBvIGRpbmFtaWNraW0gdmFyaWphYmxhbWEsIHUgYnVkdWNpbSB2ZXpiYW1hLCBwcmVkbGF6ZW0gZGEgc2Ugc2tyb3ogaXpiYWNlIGl6IHNlbGVrY2lqZSBpeiByYXpsb2dhIHN0byBuaXN1IG1vbm90b25lLCBuYWltZSwgYnVkdWNpIGRhIG92ZSB2YXJpamFibGUgbW9ndSB1emltYXRpIGtha28gbmVnYXRpdm5lIHRha28gaSBwb3ppdGl2bmUgdnJlZG5vc3RpLiBQcmltZXJhIHJhZGksIG1vZ3VjIGplIHNsZWRlY2kgc2x1Y2FqLCByZWNpbW8gZGEgaW1hbW8gZHZhIHByZWR1emVjYSAkWF57WzFdfSQgaSAkWF57WzJdfSQsIHUgcm9rdSBvZCBkdmUgZ29kaW5lIG9uaSBzdSBvc3R2YXJpbGkgc2xlZGVjZSB2cmVkbm9zdGkgbmVrb2cgcmFjaWphIGtvamkgamUgb2JybnV0byBwb3ZlemFuIHNhIGRpZm9sdG9tICh2ZWNpIHJhY2lvLW1hbmppIFBEKTogIA0KJCQgdDpYX3t0fV57WzFdfT0tMC41LCBYX3t0fV57WzJdfT0wLjcgXFwgdCsxOlhfe3QrMX1ee1sxXX09LTAuOSwgWF97dCsxfV57WzJdfT0wLjkgJCQgIA0KVGFrbyBkYSB1a29saWtvIHNhZGEgaXpyYWN1bmFtbyByYXN0IG92b2cgcmFjaWphIHphIG9iYSBwcmVkdXplY2EgZG9iaWphbW86ICANCiQkUl97eF57WzFdfX09XGZyYWN7WF97dCsxfV57WzFdfX17WF97dH1ee1sxXX19LTE9ODAgXCVcXCBSX3t4XntbMl19fT1cZnJhY3tYX3t0KzF9XntbMl19fXtYX3t0fV57WzJdfX0tMT0yOFwlICQkDQoNCiwgc3RvIGJpIHpuYWNpbG8gZGEgcHJlZHV6ZWNlIDEgaW1hIGJvbGppIFBEIG9kIHByZWR1emVjYSAyIHBvIHBvY2V0bm9qIGhpcG90ZXppLCBhIHRvIG5lIG1vemUgYml0aSBqZXIgamUgcG96aWNpamEgcHJlZHV6ZWNhIDEgb2Qgc3RhcnRhIGJpbGEgbG9zaWphIGkgam9zIHNlIHBvZ29yc2FsYSB1IHNsZWRlY2loIGdvZGludSBkYW5hLiBPdm8gamUgZ2xhdm5pIHJhemxvZyB6Ym9nIGtvZ2EsIHZlcm92YXRubywgb3Zha3ZlIHZhcmlqYWJsZSBuaXN1IHBva2F6YWxlIGpha3UgZGlza3JpbWluYXRpdm51IG1vYy4gS2FkYSBzZSBvZGx1Y2ltbyB1IGJ1ZHVjbm9zdGkgemEgcHJvcmFjdW4gcmFzdGEga2FvIHBvdGVuY2lqYWxudSB2YXJpamFibHUsIHBvdHJlYm5vIGplIGRhIG9uIHByZSBzdmVnYSBidWRlIHJhY3VuYXQgbmEgbW9ub3RvbmltIHZhcmlqYWJsYW1hLCBrb2plIG5lIG1lbmphanUgem5hayEgIA0KDQpOYXN0YXZsamFtbzogIA0KDQoNCiMjI1RyZXRtYW4gcHJvYmxlbWF0aWNuaWggdmFyaWphYmxpICANCg0KT3Zha28sIGdlbmVyYWxubywgb25vIHN0byBuaXNtbyAobmlzbW8gaHRlbGkga29tZW50YXJpc2F0aSkga29tZW50YXJpc2FsaSBzdSBzaW1ldHJpY25vc3RpIHZhcmlqYWJsaS4gUG96aXRpdm5vIGFzaW1ldHJpY25vIGplIGJhciBwb2xhIHBvc21hdHJhbmloIHZhcmlqYWJsaSB0YWtvIGRhIGJpIHZhbGphbGEgbmVrYSB2cnN0YSBsb2dhcml0bW92YW5lIHRyYW5zZm9ybWFjaWplIHV6IHZvZGplbmplIHJhY3VuYSBvIG5lZ2F0aXZuaW0gdnJlZG5vc3RpbWEgKG5hIHByaW1lciB0cmFuc2Zvcm1hY2lqYSB0aXBhOg0KJFxsb2codmFyICsgXG1pbih2YXIpICsgMSkpJCBiaSBzZSBwb2JyaW51bGEgemEgbmVnYXRpdm5lIHZyZWRub3N0aS4gQm94DQpaYSBuZWdhdGl2bnUgYXNpbWV0cmljbm9zdCBiaSBrb3Jpc3RpbGkgZXZlbnR1YWxubyBla3Nwb25lbmNpamFsbnUgdHJhbnNmb3JtYWNpanUuIFZpZGVjZW1vIHBvc2xlIHBydm9nIHN0ZXB3aXNlYSBpIEFVUk9DLWEuICANCg0KSXBhaywgb3ZkZSBjZW1vIHNlIGtvbmNlbnRyaXNhdGkgbmEgcGFyIHByZXRob2RubyBuYXBvbWVudXRpaCB2YXJpamFibGkuICANCg0KIyMjI1Bva3JpxIdlIG5ldG8ga2FtYXRhICANClBydm8gY2VtbyBwb2RlbGl0aSB2YXJpamFibHUgbmEgbiBpbnRlcnZhbGEuIFphIG9wdGltYWxhbiBicm9qIGludGVydmFsYSBtb3plbW8gaXNrb3Jpc3RpdGkgZHJ1Z3UgZnVua2NpanUga29qYSBpbWEgYWxnb3JpdGFtIGtvamkgYmlyYSBicm9qIGludGVydmFsYSBvZCAxMCBkbyAyMCBuYSBvc25vdnUgb2RyZWRqZW5paCBrcml0ZXJpanVtYSwgdmlkaSBoZWxwIGZ1bmtjaWplIGRvbGUuDQoNCmBgYHtyfQ0KI2tyZWlyYW0gdGFiZWx1IG9kIHBva3JpY2EgbmV0byBrYW1hdGEgaSBpbmRpa2F0b3JhIGRlZmF1bHQtYQ0KZGF0YTwtbHJnZS50cmFpbmluZ1ssYygiZGVmYXVsdC55IiwiUG9rcmljZV9uZXRvX2thbWF0YSIpXQ0KDQpJViA8LSBjcmVhdGVfaW5mb3RhYmxlcyhkYXRhPWRhdGEsDQogICAgICAgICAgICAgICAgICAgICAgICB5PSJkZWZhdWx0LnkiLCANCiAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFsbGVsPUZBTFNFKQ0KSVZfVmFsdWUgPSBkYXRhLmZyYW1lKElWJFN1bW1hcnkpDQpJVl9WYWx1ZQ0KSVYkVGFibGVzDQpwbG90X2luZm90YWJsZXMoSVYsIlBva3JpY2VfbmV0b19rYW1hdGEiKQ0KYGBgDQpEYWtsZSBvcHRpbXVtIGplIDEwLCBpbWFqdWNpIHUgb2J6aXIgbmVkb3N0YWp1Y2UgdnJlZG5vc3RpIGthbyAxMSBrYXRlZ29yaWp1LiBTYWRhIHJhY3VuYW1vIGZpdGluZyBmdW5rY2lqdSB0cmFuc2Zvcm1hY2lqZS4gR2VuZXJhbG5vLCBtb2dsaSBiaXNtbyBwb2RlbGl0aSB2YXJpamFibHUgdSA4IGthdGVnb3JpY2tpaCwgYWxpIGphIGJpaCBpemJlZ2FvIHRvLiBIYWpkZSBwcnZvIGRhIHZpZGltbyBlbXBpcmlqc2t1IGRpc3RyaWJ1Y2lqdSwgcGEgZGEgZml0dWplbW8uDQpgYGB7cn0NCg0KI2l6cmFjdW5hbSBtZWRpamFudSBwbyBzdmFrb20gYmludQ0KDQoNCiNvdm8gamUgdWplZG5vIGkgcHJ2aSBwdXQgZGEga29yaXN0aW0gbGlzdHUgdSBSLXUNCmNhbGlicmF0ZV9wYXJhbWV0ZXJzPWZ1bmN0aW9uKHRhYmVsYSwgdmFyaWphYmxhLCBkZWZhdWx0LnZhcmlqYWJsYSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicm9qX2Jpbm92YT04LCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG91dGxpZXIucXVhbnQ9YygwLjk5LDAuMDEpKXsNCiAgdGFiZWxhJGlkPC0xOm5yb3codGFiZWxhKQ0KICANCiAgI3Byb3ZlcmEgZGEgbGkgamUgY2xhc2EgdGFiZWxlIGRhdGEudGFibGUgb2JqZWthdA0KICBpZighaXMuZGF0YS50YWJsZSh0YWJlbGEpKSB0YWJlbGE9YXMuZGF0YS50YWJsZSh0YWJlbGEpDQogIA0KICAjbW9yYSBvdmFrbyBkYSBiaSBzZSB1IGZ1bmtjaWppIHBvenZhbyBuYXppdiBrYXNuaWplIHUgZXZhbCBmdW5rY2lqaSwgYmFnIHUgZGF0YS50YWJsZSBrb2ppIHNlIG92YWtvIHByZXZhemlsYXppDQogIHZhcmlqYWJsYT1hcy5uYW1lKHZhcmlqYWJsYSkNCiAgZGVmYXVsdC52YXJpamFibGE9YXMubmFtZShkZWZhdWx0LnZhcmlqYWJsYSkNCiAgDQoNCiAgIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGtvbnRpbnVhbG5hIHRyYW5zZm9ybWFjaWphICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMNCiAgIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCiAgICAjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyNMb2cgb2RkcyB0cmFuc2Zvcm1hY2lqYSMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCiAgICAgICNrcmVpcmFtIGthdGVnb3JpY2t1IHZhcmlqYWJsdS1rb2xvbnUgdSB0YWJlbGkga29qYSBuYW0gZ292b3JpIGtvamVtIHF1YW50aWx1LCBkZWNpbHUuLiAoemF2aXNubyBvZCBicm9qYSBiaW5vdmEpIHByaXBhZGEgZGF0YSBvYnNlcnZhY2lqYSB2YXJpamFibGUNCiAgICAgIHRhYmVsYVssdmFyaWphYmxhX0Jpbjo9cXVhbnRjdXQoDQogICAgICAgIHRhYmVsYVssZXZhbCh2YXJpamFibGEpXSwNCiAgICAgICAgcSA9IHNlcSgwLDEsYnkgPSAxL2Jyb2pfYmlub3ZhKQ0KICAgICAgICApDQogICAgICAgIF0NCiAgICAgIA0KICAgICAgI2tyZWlyYW0gdGFiZWx1IG1lZGlqYW5hIHNhIG9kZ292YXJhanVjaW0gcGRqZXZpbWENCiAgICAgIHRlbXBfZGF0YTwtbmEub21pdCgNCiAgICAgICAgdGFiZWxhWywuKHByb2I9c3VtKGV2YWwoZGVmYXVsdC52YXJpamFibGEpKS8oLk4pLA0KICAgICAgICAgICAgICAgICAgbWVkaWFucyA9IG1lZGlhbihldmFsKHZhcmlqYWJsYSkpKSwNCiAgICAgICAgICAgICAgIGJ5ID0gdmFyaWphYmxhX0Jpbl0NCiAgICAgICAgKVtvcmRlcihtZWRpYW5zKV0NCiAgICAgIA0KICAgIA0KICAgICAgI2ZpdHVqZW0gZnVua2NpanUgbmEgbWVkaWphbmUgcHJlbWEgcGRqZXZpbWENCiAgICAgIGxvZXNfZml0PC1sb2Vzcyhwcm9ifm1lZGlhbnMsZGF0YT10ZW1wX2RhdGEgKQ0KICAgICAgeTwtdGFiZWxhWyxldmFsKHZhcmlqYWJsYSldDQogICAgICANCiAgICAgICNzcmVkanVqZW0gYXV0bGplcmUgcHJlIGZvcmVjYXN0YQ0KICAgICAgdWJvdW5kPC1xdWFudGlsZSh4ID0geSwgcHJvYnMgPSBvdXRsaWVyLnF1YW50WzFdLG5hLnJtID0gVCkNCiAgICAgIGxib3VuZDwtcXVhbnRpbGUoeCA9IHksIHByb2JzID0gb3V0bGllci5xdWFudFsyXSxuYS5ybSA9IFQpDQogICAgICANCiAgICAgICAgI3NyZWRpIHRlIGF1dGxhamVyZSBicmUNCiAgICAgIHlbeT51Ym91bmRdPC11Ym91bmQNCiAgICAgIHlbeTxsYm91bmRdPC1sYm91bmQNCiAgICANCiAgICAgICNmb3JrYXN0dWplbSBrb21wbGV0IHZyZWRub3N0aSB2YXJpamFibGUgc2hvZG5vIGRvYmlqZW5pbSB2cmVkbm9zdGltYSBmaXQgZnVua2NpamUNCiAgICAgIA0KICAgICAgbWVkaWFuLkg8LXRhYmVsYVtldmFsKGRlZmF1bHQudmFyaWphYmxhKT09MCxtZWRpYW4oZXZhbCh2YXJpamFibGEpLG5hLnJtID0gVCldDQogICAgICBtZWRpYW4uRDwtdGFiZWxhW2V2YWwoZGVmYXVsdC52YXJpamFibGEpPT0xLG1lZGlhbihldmFsKHZhcmlqYWJsYSksbmEucm0gPSBUKV0NCiAgICAgIA0KICAgICAgeVtpcy5uYSh5KSAmIHRhYmVsYVssZXZhbChkZWZhdWx0LnZhcmlqYWJsYSldPT0xXTwtbWVkaWFuLkQNCiAgICAgIHlbaXMubmEoeSkgJiB0YWJlbGFbLGV2YWwoZGVmYXVsdC52YXJpamFibGEpXT09MF08LW1lZGlhbi5IDQogICAgICAgIA0KICAgICAgcDwtcHJlZGljdChsb2VzX2ZpdCx5KQ0KICAgIA0KICAgICAgI3BbcDwwXT0wLjAwMDAwMSAjemEgc3Zha2kgc2x1Y2FqDQogICAgICAjIHBbcD4xXT0wLjk5OTk5OQ0KICAgICAgI3RyZWJhanUgbWkgbG9nIG9kZHMgYSBuZSBwZGpldmkNCiAgDQogICAgICB0YWJlbGFbLHRyYW5zZm9ybWlzYW5hX3ZhcmlqYWJsYTo9bG9nKHAvKDEtcCkpXQ0KICAgIA0KICAgICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjI0JPWCBDT1ggdHJhbnNmb3JtYWNpamEjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIA0KICAgICAgDQogICAgICAjIHRvIGZpbmQgb3B0aW1hbCBsYW1iZGENCiAgICAgIHZlY3RvcjwtdGFiZWxhWyxldmFsKHZhcmlqYWJsYSldDQogICAgICBsYW1iZGEgPSBCb3hDb3gubGFtYmRhKCB2ZWN0b3IgKQ0KICAgICAgIyBub3cgdG8gdHJhbnNmb3JtIHZlY3Rvcg0KICAgICAgQm94LmNveC52YXJpamFibGEgPSBCb3hDb3goIHZlY3RvciwgbGFtYmRhKQ0KICAgICAgdGFiZWxhWyxCb3guY294LnZhcmlqYWJsYTo9Qm94LmNveC52YXJpamFibGFdDQogICAgICANCiAgDQogICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQogICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiaW5vdmkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjDQogICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQogIA0KICAgICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjI2xvZyBvZGRzIGJpbm92aSMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KICAgIA0KICAgICNyYWN1bmFtIHBkamV2ZSB6YSBzdmFraSBiaW4gaSBkb2RlbGp1amVtIGloIHBvcmVkIHN0YXJlIHZyZWRub3N0aSB2YXJpamFibGUNCiAgICAgICAgI05BIHByZXR2YXJhbSB1IGNoYXJhY3RlciBkYSBiaWggc3JhY3VuYW8gaSB6YSBuamVnYSBERg0KICAgDQogICAgICB0YWJlbGFbLHZhcmlqYWJsYV9CaW5fbnVtZXJpYzo9YXMubnVtZXJpYyh2YXJpamFibGFfQmluKV1bDQogICAgICAgICx2YXJpamFibGFfQmluX251bWVyaWM6PWFzLmNoYXJhY3Rlcih2YXJpamFibGFfQmluX251bWVyaWMpXVsNCiAgICAgICAgICBpcy5uYSh2YXJpamFibGFfQmluX251bWVyaWMpLHZhcmlqYWJsYV9CaW5fbnVtZXJpYzo9Ik5BIl0NCiAgICAgIA0KICAgICAgdGFiZWxhWyxwcm9iOj1zdW0oZXZhbChkZWZhdWx0LnZhcmlqYWJsYSkpLyguTiksYnkgPSB2YXJpamFibGFfQmluX251bWVyaWNdDQogICAgICANCiAgICAgICAgI3JlY29yZCBhIHBsb3QNCiAgICAgIHAxPWdncGxvdChkYXRhPXRhYmVsYSwgYWVzKHZhcmlqYWJsYV9CaW5fbnVtZXJpYykpK2dlb21fYmFyKGFlcyh3ZWlnaHQ9ZXZhbChkZWZhdWx0LnZhcmlqYWJsYSkpKQ0KICAgICAgDQogICAgICAjYWxpIHRyZWJhanUgbWkgbG9nIG9kZHMgbmFyYXZubw0KICAgICAgdGFiZWxhWyxvZGRzOj0ocHJvYi8oMS1wcm9iKSldDQogIA0KICAgICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjd29lIGJpbm92aSMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQogIA0KICAgICAgZGF0YTwtZGF0YS5mcmFtZSgNCiAgICAgICAgZGVmYXVsdC52YXJpamFibGE9dGFiZWxhWyxldmFsKGRlZmF1bHQudmFyaWphYmxhKV0sDQogICAgICAgIGNvbnRpbnVhbG5hX3ZhcmlqYWJsYT10YWJlbGFbLGV2YWwodmFyaWphYmxhKV0pDQogICAgDQogICAgICBXT0UgPSBjcmVhdGVfaW5mb3RhYmxlcyhkYXRhID0gYXMuZGF0YS5mcmFtZShkYXRhKSwNCiAgICAgICAgICAgICAgICAgICAgICB5PSJkZWZhdWx0LnZhcmlqYWJsYSIsIA0KICAgICAgICAgICAgICAgICAgICAgIHBhcmFsbGVsPUZBTFNFLA0KICAgICAgICAgICAgICAgICAgICAgIGJpbnMgPSBicm9qX2Jpbm92YSkNCiAgICAgIA0KICAgICAgd29lID1XT0UkVGFibGVzJGNvbnRpbnVhbG5hX3ZhcmlqYWJsYVssYygxLDQpXQ0KICAgICANCiAgICAgICNha28gcG9zdG9qZSBtaXNzaW5nIHZhbHVlcyANCiAgICAgIGlmKHdvZVsxLDFdPT0iTkEiKXsNCiAgICAgICB3b2UkInZhcmlqYWJsYV9CaW5fbnVtZXJpYyI9YygiTkEiLDE6YnJval9iaW5vdmEpIA0KICAgICAgfSBlbHNlIHsNCiAgICAgICAgd29lJCJ2YXJpamFibGFfQmluX251bWVyaWMiPWFzLmNoYXJhY3RlcigxOmJyb2pfYmlub3ZhKQ0KICAgICAgfQ0KICAgICAgIA0KICAgICAgd29lLnBsb3Q8LXBsb3RfaW5mb3RhYmxlcyhXT0UsImNvbnRpbnVhbG5hX3ZhcmlqYWJsYSIpDQogICAgDQogICAgICAjcHJlYmFjaSBrYXRlZ29yaWplIHUgYnJvamV2ZSBwYSBuamloIHUgY2hhcmFjdGVyIHpib2cgbmEgaXogcHJldGhvZG5lIHRhYmVsZSwgcGEgbmEgdSBjaGFyYWN0ZXIgam9zIGplZG5vbSBkYSBiaSBtb2dhbyBkYSBnYSB2bG9va2FwdWplDQogICAgICANCiAgICAgIA0KICAgIA0KICAgICAgdGFiZWxhPC1tZXJnZSh4PXRhYmVsYSx5PXdvZSwgYWxsLnggPSBUKVtvcmRlcihpZCldWyxpZDo9TlVMTF0jdmFyaWphYmxhX0Jpbl9udW1lcmljIGplIHRyYXplbmEgdmFydWphYmxhDQogIA0KICANCiAgDQogICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFVQyB2cmVkbm9zdGkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMNCiAgIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQogICAgICANCiAgICAjcmFjdW5hbSBhdWMgdnJlZG5vc3QsIHN0YXJ1IHBhIG5vdnUgIG5vb29vdnUgDQogICAgI3N0YXJhDQogIGF1cm9jLnM8LWF1YygNCiAgICAgIGFzLm51bWVyaWModGFiZWxhWyxldmFsKGRlZmF1bHQudmFyaWphYmxhKV0pLA0KICAgICAgYXMubnVtZXJpYyh0YWJlbGFbLGV2YWwodmFyaWphYmxhKV0pKQ0KICAgIGF1Yy52cmVkbm9zdC5wcmU8LWFzLm51bWVyaWMoYXVyb2MucykNCiAgICAjbm92YQ0KICBhdXJvYy5uPC1hdWMoDQogICAgICBhcy5udW1lcmljKHRhYmVsYVssZXZhbChkZWZhdWx0LnZhcmlqYWJsYSldKSwNCiAgICAgIGFzLm51bWVyaWModGFiZWxhWyx0cmFuc2Zvcm1pc2FuYV92YXJpamFibGFdKSkNCiAgYXVjLnZyZWRub3N0LnBvc2xlPC1hcy5udW1lcmljKGF1cm9jLm4pDQoNCiAgIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICBPc3RhbGkgR3JhZmljaSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMNCiAgIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCiAgDQogIGNvbC5udW0uZGVmYXVsdDwtZ3JlcCgiZGVmYXVsdCIsIGNvbG5hbWVzKHRhYmVsYSkpDQogIGNvbC5udW0udmFyaWphYmxhPC13aGljaChjb2xuYW1lcyh0YWJlbGEpPT12YXJpamFibGEpDQogIA0KICBvc3RhbGlfcGxvdG92aV9wcmU9cGxvdGluZyh0YWJlbGEsY29sLm51bS52YXJpamFibGEsY29sLm51bS5kZWZhdWx0KQ0KICAgIA0KICBjb2wubnVtLmRlZmF1bHQ8LWdyZXAoImRlZmF1bHQiLCBjb2xuYW1lcyh0YWJlbGEpKQ0KICBjb2wubnVtLnZhcmlqYWJsYTwtd2hpY2goY29sbmFtZXModGFiZWxhKT09InRyYW5zZm9ybWlzYW5hX3ZhcmlqYWJsYSIpDQogIG9zdGFsaV9wbG90b3ZpX3Bvc2xlPXBsb3RpbmcodGFiZWxhLGNvbC5udW0udmFyaWphYmxhLGNvbC5udW0uZGVmYXVsdCkNCiAgDQogIGNvbC5udW0udmFyaWphYmxhPC13aGljaChjb2xuYW1lcyh0YWJlbGEpPT0iQm94LmNveC52YXJpamFibGEiKQ0KICBib3guY294X3Bsb3Rvdmk8LXBsb3RpbmcodGFiZWxhLCBjb2wubnVtLnZhcmlqYWJsYSwgY29sLm51bS5kZWZhdWx0KQ0KICANCiAgb3V0cHV0PC1saXN0KCkNCiAgb3V0cHV0ID0gbGlzdChtb25vdG9uaWNpdHlfZ3JhcGggPSBwMSwNCiAgICAgICAgICAgICAgICBvc3RhbGlfcGxvdG92aV9wcmU9b3N0YWxpX3Bsb3RvdmlfcHJlLA0KICAgICAgICAgICAgICAgIG9zdGFsaV9wbG90b3ZpX3Bvc2xlPW9zdGFsaV9wbG90b3ZpX3Bvc2xlLA0KICAgICAgICAgICAgICAgIHdvZS5wbG90PXdvZS5wbG90LA0KICAgICAgICAgICAgICAgIGF1Yy52cmVkbm9zdD1kYXRhLmZyYW1lKGF1Yy52cmVkbm9zdC5wcmUsYXVjLnZyZWRub3N0LnBvc2xlKSwNCiAgICAgICAgICAgICAgICBmaXRfZnVua2NpamFfb2JqZWthdCA9IGxvZXNfZml0KQ0KDQogIA0KICB0YWJlbGEkdHJhbnNmb3JtaXNhbmFfdmFyaWphYmxhLT5vdXRwdXRbWzddXQ0KICBuYW1lcyhvdXRwdXQpWzddPC1wYXN0ZSh2YXJpamFibGEsIi50ciIsc2VwID0gIiIpDQogIA0KICB0YWJlbGEkb2Rkcy0+b3V0cHV0W1s4XV0NCiAgbmFtZXMob3V0cHV0KVs4XTwtcGFzdGUodmFyaWphYmxhLCIub2RkcyIsc2VwID0gIiIpDQogIA0KICB0YWJlbGEkV09FLT5vdXRwdXRbWzldXQ0KICBuYW1lcyhvdXRwdXQpWzldPC1wYXN0ZSh2YXJpamFibGEsIi5XT0UiLHNlcCA9ICIiKQ0KICANCiAgQm94LmNveC52YXJpamFibGEtPm91dHB1dFtbMTBdXQ0KICBuYW1lcyhvdXRwdXQpWzEwXTwtcGFzdGUodmFyaWphYmxhLCIuQm94LkNveCIsc2VwID0gIiIpDQogIA0KICBib3guY294X3Bsb3RvdmktPm91dHB1dFtbMTFdXQ0KICBuYW1lcyhvdXRwdXQpWzExXTwtcGFzdGUodmFyaWphYmxhLCIuQm94LkNveC5wbG90IixzZXAgPSAiIikNCiAgDQogIG91dHB1dA0KDQp9DQoNClBva3JpY2VfbmV0b19rYW1hdGFyPWNhbGlicmF0ZV9wYXJhbWV0ZXJzKGxyZ2UudHJhaW5pbmcsIGJyb2pfYmlub3ZhPTgsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJQb2tyaWNlX25ldG9fa2FtYXRhIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImRlZmF1bHQueSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG91dGxpZXIucXVhbnQ9YygwLjk1LDAuMDUpDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkNCg0KUG9rcmljZV9uZXRvX2thbWF0YXIkbW9ub3RvbmljaXR5X2dyYXBoDQpQb2tyaWNlX25ldG9fa2FtYXRhciRvc3RhbGlfcGxvdG92aV9wb3NsZQ0KYGBgDQoNCiMjIyNBc3NldCB0dXJub3Zlcg0KDQpgYGB7cn0NCkFzc2V0X3R1cm5vdmVyPWNhbGlicmF0ZV9wYXJhbWV0ZXJzKGxyZ2UudHJhaW5pbmcsIkFzc2V0X3R1cm5vdmVyIiwiZGVmYXVsdC55IikNCkFzc2V0X3R1cm5vdmVyJG9zdGFsaV9wbG90b3ZpX3Bvc2xlDQpBc3NldF90dXJub3ZlciRtb25vdG9uaWNpdHlfZ3JhcGgNCmBgYA0KDQoNCiMjS2F0ZWdvcmlja2UgcHJvbWVubGppdmU6ICANCg0KUG9zdG9qZSB0cmkga2F0ZWdvcmlja2UgdmFyaWphYmxlIGtvamUgamUgcG90cmVibm8gYW5hbGl6aXJhdGk6ICANCg0KKiAgIFNpZnJhIG9wc3RpbmUtZ2VuZXJhbG5vIHZlbGlraSBicm9qIG9wc3RpbmEgY2UgcHJhdml0aSBwcm9ibGVtLCBwcmVwb3J1a2EgamUgZGEgc2UgcG90ZW5jaWphbG5vIGl6dnJzaSBwb2RlbGEgbmEgQmVvZ3JhZCBpIG9zdGF0YWsgU3JiaWplLCBpbGksIG5hIHZlbGlrZSBncmFkb3ZlIGkgbWFsZSBvcHN0aW5lLCBnZGUgYmkgdSB2ZWxpa2UgZ3JhZG92ZSB1c2xpIEJlb2dyYWQsIE5pcywgTm92aSBTYWQsIGkgbmEga3JhanUgY2VtbyBwb2t1c2F0aSBkYSB1cG90cmViaW1vIGVrb25vbXNrdSByYXp2aWplbm9zdCBvcHN0aW5hIGthbyBwb2themF0ZWxqLiBPbmEgc2UgbWVuamEgc3Zha2UgZ29kaW5lLCBhbGkga29zdHVyIG9zdGFqZSBzbGljYW4sIHBhIGJpc21vIHUgb3ZvbSBkZWx1IHJhenZpamFuamEgbW9kZWxhIHV6ZWxpIHZyZWRub3N0IGl6IDIwMTQuIGdvZGluZSwgYSB1a29saWtvIHNlIGlzcG9zdGF2aSBrYW8gYml0YW4gZmFrdG9yIG1vemVtbyB6YXRyYXppdGkgc2VyaWp1LCBrb2phLCBtZWRqdXRpbSBuZSBpZGUgcHJlIDIwMTAuIGdvZGluZS4NCiogICBTaWZyYSBzZWt0b3JhLWdlbmVyYWxubywgbmUgcG9zdG9qaSBvcHN0ZSBtaXNsamVuamUgbyBvdm9qIHZhcmlqYWJsaSwgbml0aSBvcHJhdmRhbm9zdCB6YXN0byBiaSBvbmEgdXNsYSB1IG9icmFjdW4sIHN0b2ppIGRhIGplIGJyb2ogZGlmb2x0YSBwbyBzZWt0b3JpbWEgcmF6bGljaXQsIGFsaSBuZWtpIHNla3RvcmkgaW1hanUgdnJsbyBtYWxpIGJyb2ogb2JzZXJ2YWNpamEsIHRha28gZGEgY2VtbyBtb3JhdGkgcHJlZ3J1cGlzYXRpIHZhcmlqYWJsZSBuYSBuYWp2ZWNlIHNla3RvcmUgaSBvc3RhbGUsIHphdmlzbm8gb2QgdmVjIG5hdmVkZW5paCBrcml0ZXJpanVtYSB1IHBvY2V0a3Ugb3ZvZyBwb2dsYXZsamEuICANCiogICBTdHJhbmkgaW52ZXN0aXRvci1zaXR1YWNpamEgamUgamFzbmEgIA0KDQpgYGB7cn0NCnJwaXZvdFRhYmxlKGxyZ2UudHJhaW5pbmcua2F0ZWdvcmlja2UsDQogICAgICAgICAgICByb3dzID0gImRlZmF1bHQueSIsIA0KICAgICAgICAgICAgY29scyA9ICJTdHJhbmlfaW52ZXN0aXRvciIsDQogICAgICAgICAgICBhZ2dyZWdhdG9yTmFtZSA9ICJDb3VudCBhcyBGcmFjdGlvbiBvZiBDb2x1bW5zIikNCmBgYA0KDQoNCg0KIyMjI1NpZnJhIHNla3RvcmE6ICANCg0KDQpgYGB7cn0NCmZyZXFfdGFibGU9ZnVuY3Rpb24oZHRhLGthdGVnb3JpY2FsLGRlZmF1bHQpew0KICBrYXRlZ29yaWNhbD1hcy5uYW1lKGthdGVnb3JpY2FsKQ0KICBkZWZhdWx0PWFzLm5hbWUoZGVmYXVsdCkNCiAgdG1wPWR0YVssLk4sYnk9LihldmFsKGthdGVnb3JpY2FsKSxldmFsKGRlZmF1bHQpKV0NCiAgZnJla3ZlbmNhX3Nla3RvcjwtZGNhc3QodG1wLGV2YWwoa2F0ZWdvcmljYWwpfmV2YWwoZGVmYXVsdCksdmFsdWUudmFyPSJOIikNCiAgZnJla3ZlbmNhX3Nla3RvciRgMGBbaXMubmEoZnJla3ZlbmNhX3Nla3RvciRgMGApXT0wDQogIGZyZWt2ZW5jYV9zZWt0b3IkYDFgW2lzLm5hKGZyZWt2ZW5jYV9zZWt0b3IkYDFgKV09MA0KICB1a3Vwbm88LWZyZWt2ZW5jYV9zZWt0b3IkYDBgK2ZyZWt2ZW5jYV9zZWt0b3IkYDFgDQogIGZyZWt2ZW5jYV9zZWt0b3I8LWNiaW5kLmRhdGEuZnJhbWUoZnJla3ZlbmNhX3Nla3Rvcix1a3Vwbm8pDQogIGZyZWt2ZW5jYV9zZWt0b3JbLGRlZmF1bHRfcmF0ZTo9ZnJla3ZlbmNhX3Nla3RvciRgMWAvdWt1cG5vXQ0KICBhcy5kYXRhLmZyYW1lKGZyZWt2ZW5jYV9zZWt0b3IpDQp9DQoNCmZyZXFfdGFibGUobHJnZS50cmFpbmluZy5rYXRlZ29yaWNrZSwiU2lmcmFfc2VrdG9yIiwiZGVmYXVsdC55IikNCmBgYA0KDQpQb3NtYXRyYWp1Y2kgdGFiZWx1IHZpZGltbyBkYSB2ZWMgbmF2ZWRlbmUga3JpdGVyaWp1bWUgemFkb3ZvbGphdmFqdSBDLCBGLCBHIHNla3RvciwgdGFrbyBkYSBvc3RhbGUgbW96ZW1vIHN2cnN0YXRpIHUgcG9zZWJhbiBzZWt0b3IuIE1lZGp1dGltLCBvbm8gc3RvIHV2aWRqYW1vIGplLCBuYXphbG9zdCwgZGEgc3ZhIHRyaSBzZWt0b3JhIGltYWp1IHNsaWNudSBzdG9wdSBkaWZvbHRhIGthbyBpIGtvbXBsZXQgdXpvcmFrLCB6YWtsanVjdWplbW8gZGEgbmFtIGplIG92YSB2YXJpamFibGEgYmVza29yaXNuYS4ub3NpbSBGLCBncmFkamV2aW5hcnN0dm8sIGtvamUgbW96ZW1vIHRyZXRpcmF0aSBrYW8gcG9qZWRpbmFjbnUgdmFyaWphYmx1LiAgDQpgYGB7cn0NCmxyZ2UudHJhaW5pbmcua2F0ZWdvcmlja2UkU2lmcmFfc2VrdG9yW2xyZ2UudHJhaW5pbmcua2F0ZWdvcmlja2UkU2lmcmFfc2VrdG9yIT0iRiJdPC0iWiINCmxyZ2UudGVzdC5rYXRlZ29yaWNrZSRTaWZyYV9zZWt0b3JbbHJnZS50ZXN0LmthdGVnb3JpY2tlJFNpZnJhX3Nla3RvciE9IkYiXTwtIloiDQoNCmZyZXFfdGFibGUobHJnZS50cmFpbmluZy5rYXRlZ29yaWNrZSwiU2lmcmFfc2VrdG9yIiwiZGVmYXVsdC55IikNCg0KYGBgDQoNCmBgYHtyfQ0KZGF0YV9zaWZyYV9zZWt0b3I8LWxyZ2UudHJhaW5pbmcua2F0ZWdvcmlja2VbLGMoImRlZmF1bHQueSIsIlNpZnJhX3Nla3RvciIpXQ0KDQpJVl9zaWZyYV9zZWt0b3I8LWNyZWF0ZV9pbmZvdGFibGVzKGRhdGE9ZGF0YV9zaWZyYV9zZWt0b3IsDQogICAgICAgICAgICAgICAgICAgICAgICB5PSJkZWZhdWx0LnkiLCANCiAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFsbGVsPUZBTFNFKQ0KSVZfc2lmcmFfc2VrdG9yJFRhYmxlcw0KDQoNCmBgYA0KKkluZm9ybWF0aW9uIHZhbHVlKiBvZCAwLjA0IGRlbHVqZSBrYW8gcHJpaHZhdGxqaXYsIGFsaSBvdmRlIGltYW1vIHNhbW8gMTkgZGlmb2x0ZXJhIG5hIGplZG51IHZhcmlqYWJsdSBjaWppIGJpbiBuZSB1bGF6aSANCg0KIyMjI1NpZnJhIG9wc3RpbmU6ICANCg0KVSBjaWxqdSBpc2tvcmnFocSHZW5qYSBvdmUgdmFyaWphYmxlIHBvc2VnbnVsaSBzbW8gemEgcG9kZWxvbSBqZWRpbmljYSBMb2thbG5lIHNhbW91cHJhdmUgcG8gZWtvbm9tc2tvaiByYXp2aWplbm9zdGksIGthbyBpIG5hIGRydWd1IHBvZGVsdSBnZGUgc3UgQmVvZ3JhZCwgTm92aSBTQWQgaSBOaXMgdSBqZWRub2oga2F0ZWdvcmlqaSBrYW8gbmFqdmVjaSBncmFkb3ZpLCBhIG9zdGFsaSBncmFkb3ZpIHUgb3N0YWxpbSBrYXRlZ29yaWphbWEsIG5hIGtyYWp1IG1vemVtbyBpIGl6ZHZvaml0aSBzYW1vIEJlb2dyYWQuIFByZWdsZWRham1vIHBydm8ga2Frdm8gamUgc3RhbmplIHBvIG9zdGluYW1hOg0KDQpgYGB7cn0NCmZyZXFfdGFibGUobHJnZS50cmFpbmluZy5rYXRlZ29yaWNrZSwiU2lmcmFfb3BzdGluZSIsImRlZmF1bHQueSIpDQpgYGANClV2aWRqYW1vIGRhIEJlb2dyYWQgKG5hanZlcm92YXRuaWplKSBpIE5vdmkgU2FkIGplZGluaSBpbWFqdSBwcmVrbyAxMDAgZHV6bmlrYSwgdGFrbyBkYSBpbWEgc21pc2xhIGRlbGl0aSBuYSBCZW9ncmFkLCBOb3ZpIFNhZCBpIG9zdGFsZSBvcHN0aW5lLiBNZWRqdXRpbSwgdmlkaW1vIGRhIGplIGRlZmF1bHQgcmF0ZSB1IEJlb2dyYWR1IG9rbyAxMCUgc3RvIGplICxvcGV0LCBibGl6dSBkZWZhdWx0IHJhdGVhIHV6b3JrYSwgc2FtaW0gdGltLCBpIEJlb2dyYWQgb3RwYWRhLCBhbGkgYmkgZXZlbnR1YWxubyBtb2dsaSBrb3Jpc3RpdGkgTm92aSBTYWQga2FvIHBvc2VibnUga2F0ZWdvcmlqdS4gUG9rdXNhY2VtbyBkYSB1dmlkaW1vIGRhIGxpIG5hbSBwcmVkbG96ZW5hIHZhcmlqYWJsYSBvIHJhenZpamVub3N0aSBvcHN0aW5hIGRvbm9zaSBuZXN0byBub3ZvIChpenZyc2VuYSBqZSBtYWxhIGtvcmVrY2lqYSBrb2QgWnZlY2Fuai1hIGdkZSBqZSBkb2RhdGEgNCBrYXRlZ29yaWphIGVrb25vbXNrZSByYXp2aWplbm9zdGkgYnVkdWNpIGRhIGplIG9wc3RpbmEgc2EgS29zb3ZhKToNCg0KYGBge3J9DQojdWNpdGF2YW0gcHJpcHJlbWxqZW51IHRhYmVsdSBzYSBrYXRlZ29yaWphbWEgcmF6dmlqZW5vc3RpDQpvcHN0aW5lX3JhenZpamVub3N0IDwtIHJlYWRfZGVsaW0oIkM6L1VzZXJzL21pbG9zLmNpcG92aWMvRGVza3RvcC9Qcm9qZWt0aS9FYXJseSB3YXJuaW5nL1JhenZvam5pIGZvbGRlci9Cb3R0b20gVXAvS29yYWsgNS9vcHN0aW5lX3JhenZpamVub3N0LmNzdiIsIA0KIjsiLCBlc2NhcGVfZG91YmxlID0gRkFMU0UsIHRyaW1fd3MgPSBUUlVFKQ0KI29wc3RpbmVfcmF6dmlqZW5vc3QkU2lmcmFfb3BzdGluZTwtZmFjdG9yKG9wc3RpbmVfcmF6dmlqZW5vc3QkU2lmcmFfb3BzdGluZSkNCg0KI2piZyBtb3JhbW8gdm9kaXRpIHJhY3VuYSBvIHJlZG9zbGVkdSBvdmRlISEhISEhDQpscmdlLnRyYWluaW5nLmthdGVnb3JpY2tlJGlkICA8LSAxOm5yb3cobHJnZS50cmFpbmluZy5rYXRlZ29yaWNrZSkNCmxyZ2UudGVzdC5rYXRlZ29yaWNrZSRpZCAgPC0gMTpucm93KGxyZ2UudGVzdC5rYXRlZ29yaWNrZSkNCg0KbHJnZS50cmFpbmluZy5rYXRlZ29yaWNrZTwtbWVyZ2UobHJnZS50cmFpbmluZy5rYXRlZ29yaWNrZSxvcHN0aW5lX3JhenZpamVub3N0LGFsbC54ID0gVCkNCmxyZ2UudGVzdC5rYXRlZ29yaWNrZTwtbWVyZ2UobHJnZS50ZXN0LmthdGVnb3JpY2tlLG9wc3RpbmVfcmF6dmlqZW5vc3QsYWxsLnggPSBUKQ0KDQpscmdlLnRyYWluaW5nLmthdGVnb3JpY2tlPC1scmdlLnRyYWluaW5nLmthdGVnb3JpY2tlW29yZGVyKGxyZ2UudHJhaW5pbmcua2F0ZWdvcmlja2UkaWQpLCBdWyxpZDo9TlVMTF0NCmxyZ2UudGVzdC5rYXRlZ29yaWNrZTwtbHJnZS50ZXN0LmthdGVnb3JpY2tlW29yZGVyKGxyZ2UudGVzdC5rYXRlZ29yaWNrZSRpZCksIF1bLGlkOj1OVUxMXQ0KDQpmcmVxX3RhYmxlKGxyZ2UudHJhaW5pbmcua2F0ZWdvcmlja2UsIlJhenZpamVub3N0IiwiZGVmYXVsdC55IikNCmBgYA0KDQpJbWEgbG9naWtlIHN2cnN0YXRpIGNldHZydHUgaSB0cmVjdSBrb2xvbnUgdSBqZWRudSwgbWFkYSB0aW1lIHBvZGl6ZW1vIGRlZmF1bHQgcmF0ZSBuYSAxNiUgc2EgMTIlLCB0cmViYSBpbWF0aSB1IG9iemlyIGRhIGplIHUgb3Z1IGtvbG9udSB1c2xvIGkgcHJlZHV6ZWNlIGtvamUgamUgc2EgS29zb3ZhIGtvamUgamUgcmFuaWplIGJpbG8gc3Zyc3Rhbm8gdSBvdnUga2F0ZWdvcmlqdSwgYSBrb2plIGplIGRpZm9sdGlyYWxvLiBUaW1lIGJpIGJyb2ogb2JzZXJ2YWNpamEgdSBrbGFzaSAzIGJpbyAkOTlcYXBwcm94MTAwJC4gS29yaXNjZW5qZSBXT0UgaSBJViB1IHNsdWNhanUgdmVsaWtpaCBwcmVkdXplY2EsIGdlbmVyYWxubywgbmlqZSBpenZvZGxqaXZvLCB1c2xlZCBtYWxvZyBicm9qYSBkaWZvbHRlcmEgcG8ga2xhc2kgZmFrdG9yc2tlIHZhcmlqYWJsZSAoW143XSBwcmVkbGF6ZSBiYXIgNTAgZGlmb2x0ZXJhIHBvIGthdGVnb3Jpamkga2xhc2lmaWthY2lqZSksIGlwYWsgcG9nbGVkYWNlbW8gb3ZhIGR2YSBzdGF0aXN0aWthIGthbyBwdXRva2F6IGkgaW1hdGkgdSB2aWR1IHByZWRsb2cgW144XSBnZGUgbmF2b2RpIHphIElWIHN0YXRpc3RpayBzbGVkZWNlOg0KDQoqICAgVWtvbGlrbyBqZSBtYW5qaSBvZCAwLjAyLCBuaWplIG5hbSBvZCBwcmVrZSB2YXpub3N0aQ0KKiAgIFVrb2xpa28gamUgaXptZWRqdSAwLjAyIGkgMC4xIG9uZGEgcG9zdG9qaSBzbGFiYSBkaXNrcmltaW5hY2lqYSBpIHZlemEgc2EgcmFjaWpvbSBzYW5zaQ0KKiAgIFVrb2xpa28gamUgaXptZWRqdSAwLjEgaSAwLjMgb25kYSBwb3N0b2ppIHNyZWRuamUgamFrYSB2ZXlhIHNhIHJhY2lqb20gc2Fuc2kgaSANCiogICBQcmVrbyAwLjMgb3luYWNhdmEgc2pham51IHBvdmV5YW5vc3Qgc2EgZGlza3JpbWluYWNpam9tIGkgcmFjaWpvbSBzYW5zaSAoU3Jwc2tpIHphICpHb29kL0JhZCBvZGRzIHJhdGlvKikgIA0KDQpTcG9qaWxpIHNtbyA0IGkgMyBrYXRlZ29yaWp1DQoNCmBgYHtyfQ0KI2tyZWlyYW0gbm92dSB2YXJpamFibHUgZ2RlIDQgcHJpcGFqYW0gM2pjaQ0KbHJnZS50cmFpbmluZy5rYXRlZ29yaWNrZSRSYXp2aWplbm9zdFtscmdlLnRyYWluaW5nLmthdGVnb3JpY2tlJFJhenZpamVub3N0PT00XTwtMw0KbHJnZS50ZXN0LmthdGVnb3JpY2tlJFJhenZpamVub3N0W2xyZ2UudGVzdC5rYXRlZ29yaWNrZSRSYXp2aWplbm9zdD09NF08LTMNCmZyZXFfdGFibGUobHJnZS50cmFpbmluZy5rYXRlZ29yaWNrZSwiUmF6dmlqZW5vc3QiLCJkZWZhdWx0LnkiKQ0KYGBgDQpgYGB7cn0NCg0KZGF0YV9vcHN0aW5lX3BvX3JhenZpamVub3N0aTwtbHJnZS50cmFpbmluZy5rYXRlZ29yaWNrZVssYygiZGVmYXVsdC55IiwiUmF6dmlqZW5vc3QiKV0NCklWX29wc3RpbmVfcG9fcmF6dmlqZW5vc3RpPC1jcmVhdGVfaW5mb3RhYmxlcyhkYXRhPWRhdGFfb3BzdGluZV9wb19yYXp2aWplbm9zdGksDQogICAgICAgICAgICAgICAgICAgICAgICB5PSJkZWZhdWx0LnkiLCANCiAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFsbGVsPUZBTFNFKQ0KDQpJVl9vcHN0aW5lX3BvX3JhenZpamVub3N0aSRUYWJsZXMNCg0KYGBgDQpEb2JpbGkgc21vIElWIG9rbyAwLjA3IHN0byB6YWRvdm9samF2YSBtZWRqdXRpbSBqYWtvIGplIG1hbGkgYnJvaiBkaWZvbHRhIHUga2F0ZWdvcmlqaSAzIGltYWp1Y2kgdSB2aWR1IGJyb2ogb3BzdGluYSBrb2plIHNwYWRhanUgdSBuanUsIHNwYWphbW8gMiBpIDMNCmBgYHtyfQ0KI2tyZWlyYW0gbm92dSB2YXJpamFibHUgZ2RlIDMgaSAyIHNwYWphbQ0KbHJnZS50cmFpbmluZy5rYXRlZ29yaWNrZSRSYXp2aWplbm9zdFtscmdlLnRyYWluaW5nLmthdGVnb3JpY2tlJFJhenZpamVub3N0PT0zXTwtMg0KbHJnZS50ZXN0LmthdGVnb3JpY2tlJFJhenZpamVub3N0W2xyZ2UudGVzdC5rYXRlZ29yaWNrZSRSYXp2aWplbm9zdD09M108LTINCg0KZnJlcV90YWJsZShscmdlLnRyYWluaW5nLmthdGVnb3JpY2tlLCJSYXp2aWplbm9zdCIsImRlZmF1bHQueSIpDQpgYGANCmBgYHtyfQ0KZGF0YV9vcHN0aW5lX3BvX3JhenZpamVub3N0aTwtbHJnZS50cmFpbmluZy5rYXRlZ29yaWNrZVssYygiZGVmYXVsdC55IiwiUmF6dmlqZW5vc3QiKV0NCklWX29wc3RpbmVfcG9fcmF6dmlqZW5vc3RpPC1jcmVhdGVfaW5mb3RhYmxlcyhkYXRhPWRhdGFfb3BzdGluZV9wb19yYXp2aWplbm9zdGksDQogICAgICAgICAgICAgICAgICAgICAgICB5PSJkZWZhdWx0LnkiLCANCiAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFsbGVsPUZBTFNFKQ0KDQpJVl9vcHN0aW5lX3BvX3JhenZpamVub3N0aSRTdW1tYXJ5DQpgYGANCk9rbyAwLjA0IHN0byBiaSBtb2dsbyBkYSBuYW0gem5hY2kgbmVzdG8NCg0KUG9rdXNham1vIHNhZGEgc2EgTm92aW0gU2Fkb206DQoNCmBgYHtyfQ0KbHJnZS50cmFpbmluZy5rYXRlZ29yaWNrZSRTaWZyYV9vcHN0aW5lW2xyZ2UudHJhaW5pbmcua2F0ZWdvcmlja2UkU2lmcmFfb3BzdGluZSE9Ijg5MDEwIl08LSIwMDAwIg0KbHJnZS50ZXN0LmthdGVnb3JpY2tlJFNpZnJhX29wc3RpbmVbbHJnZS50ZXN0LmthdGVnb3JpY2tlJFNpZnJhX29wc3RpbmUhPSI4OTAxMCJdPC0iMDAwMCINCg0KZnJlcV90YWJsZShscmdlLnRyYWluaW5nLmthdGVnb3JpY2tlLCJTaWZyYV9vcHN0aW5lIiwiZGVmYXVsdC55IikNCmBgYA0KDQpgYGB7cn0NCmRhdGFfMm9wc3RpbmU8LWxyZ2UudHJhaW5pbmcua2F0ZWdvcmlja2VbLGMoImRlZmF1bHQueSIsIlNpZnJhX29wc3RpbmUiKV0NCklWXzJvcHN0aW5lPC1jcmVhdGVfaW5mb3RhYmxlcyhkYXRhPWRhdGFfMm9wc3RpbmUsDQogICAgICAgICAgICAgICAgICAgICAgICB5PSJkZWZhdWx0LnkiLCANCiAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFsbGVsPUZBTFNFKQ0KDQpJVl8yb3BzdGluZSRTdW1tYXJ5DQpgYGANCklwYWsgY2VtbyBpY2kgc2Egb3BzdGluYW1hIHBvIHJhenZpamVub3N0aQ0KDQojIyMjU3RyYW5pIGludmVzdGl0b3IgIA0KDQpQb2dsZWRham1vIHBydm8gZnJla3ZlbmNpb251IHRhYmVsdQ0KDQpgYGB7cn0NCmZyZXFfdGFibGUobHJnZS50cmFpbmluZy5rYXRlZ29yaWNrZSwiU3RyYW5pX2ludmVzdGl0b3IiLCJkZWZhdWx0LnkiKQ0KYGBgDQpQb3N0b2ppIG9jaWdsZWRuYSByYXpsaWthLCBpbWFqdWNpIHUgdmlkdSBkYSBvdmRlIGltYW1vIHNhbW8gZHZlIHZhcmlqYWJsZSwgdG8gamUgaSBvY2VraXZhbm8sIGhhamRlIGRhIHZpZGltbyBJVjoNCmBgYHtyfQ0KZGF0YV9zdHJhbmlfaW52ZXN0aXRvcjwtbHJnZS50cmFpbmluZy5rYXRlZ29yaWNrZVssYygiZGVmYXVsdC55IiwiU3RyYW5pX2ludmVzdGl0b3IiKV0NCklWX3N0cmFuaV9pbnZlc3RpdG9yPC1jcmVhdGVfaW5mb3RhYmxlcyhkYXRhPWRhdGFfc3RyYW5pX2ludmVzdGl0b3IsDQogICAgICAgICAgICAgICAgICAgICAgICB5PSJkZWZhdWx0LnkiLCANCiAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFsbGVsPUZBTFNFKQ0KDQpJVl9zdHJhbmlfaW52ZXN0aXRvciRUYWJsZXMNCmBgYA0KSW1hbW8gSVYgb2tvIDAuMDMuIFV6ZWNlbW8gb3Zha28uDQoNCg0KDQojIyNFdmFsdWFjaWphIHJlZ3Jlc2lqZQ0KDQpEb3NhZGFzbmppIHJlenVsdGF0aToNCg0KT3RwYWRhbmplIHVzbGVkIGBOQWAgdnJlZG5vc3RpLCBwcmV6aXZlbGUgc3Ugc2xlZGVjZSB2YXJpamFibGU6DQpgYGB7cn0NCnN1bW1hcnlfdGFibGU8LWFzLmRhdGEuZnJhbWUoc3VtbWFyeV90YWJsZSkNCnByZXppdmVsaS5OQTwtcm93bmFtZXMoc3VtbWFyeV90YWJsZVtzdW1tYXJ5X3RhYmxlJE5Bc3BlcmNlbnQ8MTAsXSkNCmtuaXRyOjprYWJsZShwcmV6aXZlbGkuTkEpDQpgYGANCg0KQ2lzY2VuamUgdXNsZWQga29yZWxhY2lqYSBpIEFVUk9DLWEgbWFuamVnIG9kIDAuNTUNCmBgYHtyfQ0KcHJleml2ZWxpLmNvcnIuQVVDPC1yb3cubmFtZXMoY2xlYW5fY29yKQ0KYGBgDQoNClByZXNlayBvdmEgZHZhIG5hc3RhdmxqYSB1IG11bHRpdmFyaWF0ZS4NCg0KYGBge3J9DQojb2RhYnJhbmk8LWMoIlJhY2lvX25vdmNhbmVfbGlrdmlkbm9zdGlfKENhc2hfcmF0aW8pIixpbnRlcnNlY3QocHJleml2ZWxpLk5BLHByZXppdmVsaS5jb3JyLkFVQykpDQpvZGFicmFuaTwtaW50ZXJzZWN0KHByZXppdmVsaS5OQSxwcmV6aXZlbGkuY29yci5BVUMpDQpgYGANCg0KDQoNCk92ZGUgcG9kc2VjYW1vIGRhIGNlbW8gaXBhayBkb2RhdGkga2FzaCByYWNpbyB1IGdydXB1LiBOaXNtbyBwcm92ZXJhdmFsaSBvdmRlIHJlZG92ZSBhbGkgYmkgdHJlYmFsbyBrYWRhIGJ1ZGVtbyByYWRpbGEgc2EgbWFsaW0gaSBzcmVkbmppbSBwcmVkdXplY2ltYS4gU3JlZGltbyBzYWRhIGBOQWAgdnJlZG5vc3RpOg0KDQpGdW5rY2lqYSB6YSBuZWRvc3RhanVjZSBpIGVrc3RyZW1lOg0KDQpgYGB7cn0NCnJlcGxhY2Vfb3V0bGllcl93aXRoX3F1YW50aWxlIDwtDQogIGZ1bmN0aW9uKHgsDQogIHF1YW50ID0gVFJVRSwNCiAgcHJvYnMgPSBjKDAuMDEsIDAuOTkpLA0KICBuYS5ybSA9IFRSVUUpIHsNCiAgaWYgKHF1YW50ID09IFQpIHsNCiAgcW50IDwtIHF1YW50aWxlKHgsIHByb2JzID0gcHJvYnMsIG5hLnJtID0gbmEucm0pICAjIGdldCAlaWxlcw0KICBVIDwtIHFudFsyXQ0KICBMIDwtIHFudFsxXQ0KICB5IDwtIHgNCiAgeVt4IDwgTF0gPC0gTCAgIyByZXBsYWNlIHZhbHVlcyBiZWxvdyBsb3dlciBib3VuZHMNCiAgeVt4ID4gVV0gPC0gVQ0KICB5DQogIH0gZWxzZSBpZiAocXVhbnQgPT0gRikgew0KICBxbnQgPC0gcXVhbnRpbGUoeCwgcHJvYnMgPSBjKC4yNSwgLjc1KSwgbmEucm0gPSBuYS5ybSkgICMgZ2V0ICVpbGVzDQogIEggPC0gMyAqIElRUih4LCBuYS5ybSA9IG5hLnJtKSAgIyBvdXRsaWVyIGxpbWl0IHRocmVzaG9sZA0KICB5IDwtIHgNCiAgeVt4IDwgKHFudFsxXSAtIEgpXSA8LQ0KICAocW50WzFdIC0gSCkgICMgcmVwbGFjZSB2YWx1ZXMgYmVsb3cgbG93ZXIgYm91bmRzDQogIHlbeCA+IChxbnRbMl0gKyBIKV0gPC0NCiAgKHFudFsyXSArIEgpICAjIHJlcGxhY2UgdmFsdWVzIGFib3ZlIGhpZ2hlciBib3VuZA0KICB5ICAjIHJldHVybnMgdHJlYXRlZCB2YXJpYWJsZQ0KICB9IA0KICANCiAgfQ0KICANCiAgDQogIHJlcGxhY2VfbWlzc2luZ193aXRoX21lZGlhbiA8LQ0KICBmdW5jdGlvbih4LA0KICBkZWZhdWx0LmNvbG9uYSA9IGFzLm5hbWUoZGVmYXVsdC55KSwNCiAgcHJvYnMgPSBjKDAuMDEsIDAuOTkpLA0KICBuYS5ybSA9IFRSVUUsDQogIHRyYWluaW5nID0gVCwNCiAgLi4uKSB7DQogIHggPCBhcy5kYXRhLmZyYW1lKHgpDQogIG1lZGlhbi4gPC0NCiAgbWVkaWFuKHgsIG5hLnJtID0gbmEucm0pDQogIG1lZGlhbi5oID0gbWVkaWFuKHhbZGVmYXVsdC5jb2xvbmEgPT0gMF0sIG5hLnJtID0gbmEucm0pDQogIG1lZGlhbi5kID0gbWVkaWFuKHhbZGVmYXVsdC5jb2xvbmEgPT0gMV0sIG5hLnJtID0gbmEucm0pDQogIA0KICBpZiAodHJhaW5pbmcgPT0gVCkgew0KICB4W2lzLm5hKHgpICYgZGVmYXVsdC5jb2xvbmEgPT0gMF0gPC0gbWVkaWFuLmgNCiAgeFtpcy5uYSh4KSAmDQogIGRlZmF1bHQuY29sb25hID09IDFdIDwtDQogIG1lZGlhbi5kDQogIH0gZWxzZSB7DQogIHhbaXMubmEoeCldIDwtIG1lZGlhbi4NCiAgfQ0KICB4DQogIH0NCiAgDQogIA0KICANCiAgDQogIHJlcGxhY2Vfb3V0bGllcl93aXRoX25hIDwtIGZ1bmN0aW9uKHgscXVhbnQgPSBUUlVFLA0KICBwcm9icyA9IGMoMC4wMSwgMC45OSksDQogIG5hLnJtID0gVFJVRSkgew0KICBpZiAocXVhbnQgPT0gVCkgew0KICBxbnQgPC0gcXVhbnRpbGUoeCwgcHJvYnMgPSBwcm9icywgbmEucm0gPSBuYS5ybSkgICMgZ2V0ICVpbGVzDQogIFUgPC0gcW50WzJdDQogIEwgPC0gcW50WzFdDQogIHkgPC0geA0KICB5W3ggPCBMXSA8LSBOQSAgIyByZXBsYWNlIHZhbHVlcyBiZWxvdyBsb3dlciBib3VuZHMNCiAgeVt4ID4gVV0gPC0gTkENCiAgeQ0KICB9IGVsc2UgaWYgKHF1YW50ID09IEYpIHsNCiAgcW50IDwtIHF1YW50aWxlKHgsIHByb2JzID0gYyguMjUsIC43NSksIG5hLnJtID0gbmEucm0pICAjIGdldCAlaWxlcw0KICBIIDwtIDMgKiBJUVIoeCwgbmEucm0gPSBuYS5ybSkgICMgb3V0bGllciBsaW1pdCB0aHJlc2hvbGQNCiAgeSA8LSBOQQ0KICB5W3ggPCAocW50WzFdIC0gSCldIDwtIE5BICAjIHJlcGxhY2UgdmFsdWVzIGJlbG93IGxvd2VyIGJvdW5kcw0KICB5W3ggPiAocW50WzJdICsgSCldIDwtIE5BICAjIHJlcGxhY2UgdmFsdWVzIGFib3ZlIGhpZ2hlciBib3VuZA0KICB5ICAjIHJldHVybnMgdHJlYXRlZCB2YXJpYWJsZQ0KICANCiAgfQ0KICB9DQogIA0KIA0KICANCiAgDQogIHJlcGxhY2VfbWlzc2luZ193aXRoX2tubiA8LSBmdW5jdGlvbih4LCByZXNwb25zZV9uYW1lID0gImRlZmF1bHQueSIsIHRyYWluaW5nID0gVCkgew0KICAgIA0KICAgIHggPC0gYXMuZGF0YS5mcmFtZSh4KQ0KDQogICAgcmVzcG9uc2U8LXhbLGV2YWwocmVzcG9uc2VfbmFtZSldDQogICAgaWYgKHRyYWluaW5nID09IEYpIHsNCiAgICAgIGlmIChhbnlOQSh4KSkgew0KICAgICAgICB4WywhbmFtZXMoeCkgJWluJSByZXNwb25zZV9uYW1lXSA8LQ0KICAgICAgICAgIGtubkltcHV0YXRpb24oeFssIW5hbWVzKHgpICVpbiUgcmVzcG9uc2VfbmFtZV0pICAjIG1pc3NpbmcgdmFsdWUgdHJlYXRtZW50DQogICAgICAgIH0NCiAgICB9IGVsc2Ugew0KICAgICAgaWYoYW55TkEoeCkpIHsNCiAgICAgICAgeFtyZXNwb25zZT09MSwhbmFtZXMoeCkgJWluJSByZXNwb25zZV9uYW1lXSA8LQ0KICAgICAgICAgIGtubkltcHV0YXRpb24oeFtyZXNwb25zZT09MSwhbmFtZXMoeCkgJWluJSByZXNwb25zZV9uYW1lXSkgICMgbWlzc2luZyB0cmVhdG1lbnQNCiAgICAgICAgfQ0KICAgICAgICANCiAgICAgIGlmIChhbnlOQSh4KSkgew0KICAgICAgICB4W3Jlc3BvbnNlPT0wLCFuYW1lcyh4KSAlaW4lIHJlc3BvbnNlX25hbWVdIDwtDQogICAgICAgICAga25uSW1wdXRhdGlvbih4W3Jlc3BvbnNlPT0wLCFuYW1lcyh4KSAlaW4lIHJlc3BvbnNlX25hbWVdKSAgIyBtaXNzaW5nIHZhbHVlIHRyZWF0bWVudCAgDQogICAgICAgIA0KICAgICAgICB9DQogICAgICANCiAgICB9DQogICAgYXMuZGF0YS50YWJsZSh4KQ0KICAgIH0NCiAgICANCiNpbnB1dERhdGFfY29udCA8LSBhcy5kYXRhLmZyYW1lIChzYXBwbHkoY2xlYW5fYlssOTozNF0sIHJlcGxhY2Vfb3V0bGllcl93aXRoX21pc3NpbmcpKSAgIyB0aGlzIHdpbGwgbWFrZSBvdXRsaWVycyBhcyBOQSANCiNzdW1tYXJ5X3RhYmxlMjwtc2FwcGx5KGlucHV0RGF0YV9jb250LG15LnN1bW1hcnksYXJnPVQpDQpgYGANCg0KS3JlaXJhbW8gemF2cnNuaSB1em9yYWs6ICANCl9fX19fX19fX19fX19fX19fX19fX18gIA0KDQpUcmV0bWFuIG5lZG9zdGFqdWNpaCBpIHRyZXRtYW4gYXV0bGFqZXJhLCBwb3RvbSBkb2RhamVtbyBrYXRlZ29yaWNrZQ0KDQpgYGB7cn0NCmZpbmFsbmlfbHJnZTwtbHJnZS50cmFpbmluZ1ssYyhvZGFicmFuaSksIHdpdGg9Rl0NCg0KI2ZpbmFsbmlfbHJnZTwtY2JpbmQuZGF0YS5mcmFtZShmaW5hbG5pX2xyZ2UsQXNzZXRfdHVybm92ZXIkQXNzZXRfdHVybm92ZXIudHIsUG9rcmljZV9uZXRvX2thbWF0YSRQb2tyaWNlX25ldG9fa2FtYXRhLnRyKQ0KDQojZmluYWxuaV9scmdlPC1hcy5kYXRhLnRhYmxlKHNhcHBseShmaW5hbG5pX2xyZ2UscmVwbGFjZV9vdXRsaWVyX3dpdGhfcXVhbnRpbGUpKQ0KZmluYWxuaV9scmdlPC1hcy5kYXRhLnRhYmxlKHNhcHBseShmaW5hbG5pX2xyZ2UscmVwbGFjZV9vdXRsaWVyX3dpdGhfbmEpKQ0KZmluYWxuaV9scmdlJGRlZmF1bHQueTwtbHJnZS50cmFpbmluZyRkZWZhdWx0LnkNCg0KZmluYWxuaV9scmdlPC1yZXBsYWNlX21pc3Npbmdfd2l0aF9rbm4oZmluYWxuaV9scmdlKQ0KDQpmaW5hbG5pX2xyZ2UkZGVmYXVsdC55PC1OVUxMDQpgYGANCg0KDQpgYGB7cn0NCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3BjaW9ubyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMNCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMNCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCkFBPC1kYXRhLmZyYW1lKDE6MTI1NSk7bj0xICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMNCmZpbmFsbmlfbHJnZSRkZWZhdWx0LnkgPC0gZGVmYXVsdC55ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMNCmZvcihpIGluIG5hbWVzKGZpbmFsbmlfbHJnZSlbImRlZmF1bHQueSIgIT0gbmFtZXMoZmluYWxuaV9scmdlKV0pIHsNCiAgDQogIG4gPSBuICsgMQ0KICB0bXAgPC0gY2FsaWJyYXRlX3BhcmFtZXRlcnMoZmluYWxuaV9scmdlLCBpLCAiZGVmYXVsdC55IikNCiAgQUEgPC0gY2JpbmQuZGF0YS5mcmFtZShBQSwgdG1wW1s3XV0pDQogIG5hbWVzKEFBKVtuXSA8LSBuYW1lcyhmaW5hbG5pX2xyZ2UpW25dDQp9DQoNCg0KZmluYWxuaV9scmdlIDwtIEFBDQpyZW1vdmUoQUEpDQpmaW5hbG5pX2xyZ2VbLCAxXSA8LSBOVUxMDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIw0KZmluYWxuaV9scmdlJGRlZmF1bHQueSA8LSBkZWZhdWx0LnkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjDQpmaW5hbG5pX2xyZ2UgPC0gYXMuZGF0YS50YWJsZShmaW5hbG5pX2xyZ2UpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMNCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KYGBgDQoNCg0KYGBge3J9DQojc3BhamFtbyBzYSBrYXRlZ29yaWNraW0gaSBza2lkYW1vIHBhciB2aXNrb3ZhIGthdGVnb3JpY2tpaCwgdmVsaWNpbmEsIHRvdGFsDQoNCmZpbmFsbmlfbHJnZSA8LQ0KICBjYmluZC5kYXRhLmZyYW1lKGZpbmFsbmlfbHJnZSwgbHJnZS50cmFpbmluZy5rYXRlZ29yaWNrZSlbLCBjKCJWZWxpY2luYSIsICJUb3RhbCIsICJTaWZyYV9zZWt0b3IiLCJTaWZyYV9vcHN0aW5lIikgOj0NCiAgTlVMTF0NCiAgDQoNCiNwcmV0dmFyYW0ga2F0ZWdvcmlja2UgdSBmYWt0b3IgZGEgYmkgaWggZ2xtIHBvc21hdHJhbyBrYW8ga2F0ZWdvcmlja2UNCmZpbmFsbmlfbHJnZSRSYXp2aWplbm9zdCA8LSBhcy5mYWN0b3IoZmluYWxuaV9scmdlJFJhenZpamVub3N0KQ0KZmluYWxuaV9scmdlJFN0cmFuaV9pbnZlc3RpdG9yIDwtDQphcy5mYWN0b3IoZmluYWxuaV9scmdlJFN0cmFuaV9pbnZlc3RpdG9yKQ0KYGBgDQoNCkR1Z28gb2Nla2l2YW5pIHRyZW51dGFrOg0KDQpgYGB7cn0NCg0KbW9kZWwubnVsbCA9IGdsbShkZWZhdWx0LnkgfiAxLA0KICAgICAgICAgICAgICAgICBkYXRhPWZpbmFsbmlfbHJnZSwNCiAgICAgICAgICAgICAgICAgZmFtaWx5ID0gYmlub21pYWwobGluaz0ibG9naXQiKQ0KICAgICAgICAgICAgICAgICApDQoNCm1vZGVsLmZ1bGwgPSBnbG0oZGVmYXVsdC55IH4gLiwNCiAgICAgICAgICAgICAgICAgZGF0YT1maW5hbG5pX2xyZ2UsDQogICAgICAgICAgICAgICAgIGZhbWlseSA9IGJpbm9taWFsKGxpbms9ImxvZ2l0IikNCiAgICAgICAgICAgICAgICAgKQ0KICAgIA0Kc3RlcChtb2RlbC5udWxsLA0KICAgICBzY29wZSA9IGxpc3QodXBwZXI9bW9kZWwuZnVsbCxsb3dlcj1tb2RlbC5udWxsKSwNCiAgICAgICAgICAgICBkaXJlY3Rpb249ImZvcndhcmQiLA0KICAgICAgICAgICAgIA0KICAgICAgICAgICAgIGRhdGE9ZmluYWxuaV9scmdlLHRyYWNlPTApDQpgYGANCg0KYGBge3J9DQptb2RlbDEgPC0gZ2xtKGZvcm11bGEgPWRlZmF1bHQueX5gUmFjaW9fbm92Y2FuZV9saWt2aWRub3N0aV8oQ2FzaF9yYXRpbylgK1N0ZXBlbl96YWR1emVub3N0aStHb3Rvdmluc2tpX2Npa2x1c18xK1ZyZW1lX25hcGxhdGVfcG90cmF6aXZhbmphK1N0b3BhX3ByaW5vc2FfbmFfc29wc3R2ZW5pX2thcGl0YWxfcHJlX29wb3Jleml2YW5qYStDZW5hX3R1ZGppaF9penZvcmFfc3JlZHN0YXZhLCBmYW1pbHkgPSBiaW5vbWlhbChsaW5rID0gImxvZ2l0IiksIA0KICAgIGRhdGEgPSBmaW5hbG5pX2xyZ2UpDQoNCg0KbW9kZWwxLmRhdGEuZnJhbWU8LWRhdGEuZnJhbWUoZml0MT1tb2RlbDEkZml0dGVkLnZhbHVlcywgZGlmMT1tb2RlbDEkbW9kZWwkZGVmYXVsdC55KQ0KDQpgYGANCg0KDQoNCg0KYGBge3J9DQpzdGVwKG1vZGVsLmZ1bGwsDQogICAgIHNjb3BlID0gbGlzdChsb3dlcj1tb2RlbC5mdWxsLHVwcGVyPW1vZGVsLm51bGwpLA0KICAgICAgICAgICAgIGRpcmVjdGlvbj0iYmFja3dhcmQiLA0KICAgICAgICAgICAgIGRhdGE9ZmluYWxuaV9scmdlLCB0cmFjZT0wKQ0KYGBgDQpgYGB7cn0NCiBtb2RlbDI8LSAgZ2xtKGZvcm11bGEgPSBkZWZhdWx0LnkgfiBgUmlnb3Jvem5pX3JhY2lvX3JlZHVrb3ZhbmVfKG1vbmV0YXJuZSlfbGlrdmlkbm9zdGlgICsgDQogICAgYFJhY2lvX25vdmNhbmVfbGlrdmlkbm9zdGlfKENhc2hfcmF0aW8pYCArIFN0ZXBlbl96YWR1emVub3N0aSArIA0KICAgIGBSYWNpb19wb2tyaWNhX2thbWF0YV96YXJhZG9tX3ByZV9rYW1hdGFfaV9wb3JlemFfKEludGVyZXN0X0NvdmVyYWdlX1JhdGlvKWAgKyANCiAgICBSYWNpb19wb2tyaWNhX29icnRuZV9pbW92aW5lICsgR290b3ZpbnNraV9jaWtsdXNfMSArIFZyZW1lX2tyZWRpdGlyYW5qYV9rdXBhY2EgKyANCiAgICBWcmVtZV9uYXBsYXRlX3BvdHJheml2YW5qYSArIFZyZW1lX3BsYWNhbmphX2RvYmF2bGphY2ltYSArIA0KICAgIFN0b3BhX3ByaW5vc2FfbmFfc29wc3R2ZW5pX2thcGl0YWxfcHJlX29wb3Jleml2YW5qYSArIFN0b3BhX3ByaW5vc2FfbmFfdWt1cG5hX3NyZWRzdHZhX3ByZV9vcG9yZXppdmFuamEgKyANCiAgICBDZW5hX3R1ZGppaF9penZvcmFfc3JlZHN0YXZhICsgVDE0ICsgVDIxICsgdWRlb191X2thcGl0YWx1ICsgDQogICAgU3RyYW5pX2ludmVzdGl0b3IgKyBSYXp2aWplbm9zdCwgZmFtaWx5ID0gYmlub21pYWwobGluayA9ICJsb2dpdCIpLCANCiAgICBkYXRhID0gZmluYWxuaV9scmdlKQ0KDQptb2RlbDIuZGF0YS5mcmFtZT1kYXRhLmZyYW1lKGZpdDI9bW9kZWwyJGZpdHRlZC52YWx1ZXMsIGRpZjI9bW9kZWwyJG1vZGVsJGRlZmF1bHQueSkNCg0KYGBgDQoNCldhbGQgc3RhdGlzdGlrOg0KDQpgYGB7cn0NCmxpYnJhcnkoY2FyKQ0KDQpBbm92YShtb2RlbDEsIHR5cGU9IklJIiwgdGVzdD0iV2FsZCIpDQpgYGANCkxhbmdyYW5nZSBtdWx0aXBsaWVyIHRlc3Q6DQoNCmBgYHtyfQ0KYW5vdmEobW9kZWwyLA0KICAgICAgbW9kZWwubnVsbCwNCiAgICAgIHRlc3Q9IkNoaXNxIikNCmBgYA0KDQoNCg0KRHJ1Z2kgbmFjaW4NCg0KYGBge3J9DQogIGF1cm9jLjE8LWF1YygNCiAgICAgIGFzLm51bWVyaWMobW9kZWwxLmRhdGEuZnJhbWUkZGlmMSksDQogICAgICBhcy5udW1lcmljKG1vZGVsMS5kYXRhLmZyYW1lJGZpdDEpKQ0KIGF1cm9jLjI8LWF1YygNCiAgICAgIGFzLm51bWVyaWMobW9kZWwyLmRhdGEuZnJhbWUkZGlmMiksDQogICAgICBhcy5udW1lcmljKG1vZGVsMi5kYXRhLmZyYW1lJGZpdDIpKQ0KYyhhdXJvYy4xLGF1cm9jLjIpDQoNCmBgYA0KDQojIyN2YWxpZGFjaW9uaSB1em9yYWsgIA0KMTA2MjY0IDk2OTQ2DQpgYGB7cn0NCmZpbmFsbmlfbHJnZS50ZXN0PC1scmdlLnRlc3RbLGMob2RhYnJhbmkpLCB3aXRoPUZdDQoNCiNmaW5hbG5pX2xyZ2U8LWNiaW5kLmRhdGEuZnJhbWUoZmluYWxuaV9scmdlLEFzc2V0X3R1cm5vdmVyJEFzc2V0X3R1cm5vdmVyLnRyLFBva3JpY2VfbmV0b19rYW1hdGEkUG9rcmljZV9uZXRvX2thbWF0YS50cikNCg0KZmluYWxuaV9scmdlLnRlc3Q8LWFzLmRhdGEudGFibGUoc2FwcGx5KGZpbmFsbmlfbHJnZS50ZXN0LHJlcGxhY2Vfb3V0bGllcl93aXRoX25hKSkNCg0KZmluYWxuaV9scmdlLnRlc3QkZGVmYXVsdC55PC1scmdlLnRlc3QkZGVmYXVsdC55DQoNCmZpbmFsbmlfbHJnZS50ZXN0PC1yZXBsYWNlX21pc3Npbmdfd2l0aF9rbm4oZmluYWxuaV9scmdlLnRlc3QsdHJhaW5pbmcgPSBGKQ0KZmluYWxuaV9scmdlLnRlc3QkZGVmYXVsdC55PC1OVUxMDQoNCg0KZmluYWxuaV9scmdlLnRlc3QgPC0NCiAgY2JpbmQuZGF0YS5mcmFtZShmaW5hbG5pX2xyZ2UudGVzdCwgbHJnZS50ZXN0LmthdGVnb3JpY2tlKVssIGMoIlZlbGljaW5hIiwgIlRvdGFsIiwgIlNpZnJhX3Nla3RvciIsIlNpZnJhX29wc3RpbmUiKSA6PQ0KICBOVUxMXQ0KICANCg0KI3ByZXR2YXJhbSBrYXRlZ29yaWNrZSB1IGZha3RvciBkYSBiaSBpaCBnbG0gcG9zbWF0cmFvIGthbyBrYXRlZ29yaWNrZQ0KZmluYWxuaV9scmdlLnRlc3QkUmF6dmlqZW5vc3QgPC0gYXMuZmFjdG9yKGZpbmFsbmlfbHJnZS50ZXN0JFJhenZpamVub3N0KQ0KZmluYWxuaV9scmdlLnRlc3QkU3RyYW5pX2ludmVzdGl0b3IgPC0NCmFzLmZhY3RvcihmaW5hbG5pX2xyZ2UudGVzdCRTdHJhbmlfaW52ZXN0aXRvcikNCg0KDQptb2RlbDEucHJlZDwtYXMubnVtZXJpYyhwcmVkaWN0KG1vZGVsMSwgbmV3ZGF0YSA9IGZpbmFsbmlfbHJnZS50ZXN0LCB0eXBlID0gInJlc3BvbnNlIikpDQptb2RlbDIucHJlZDwtYXMubnVtZXJpYyhwcmVkaWN0KG1vZGVsMiwgbmV3ZGF0YSA9IGZpbmFsbmlfbHJnZS50ZXN0LCB0eXBlID0gInJlc3BvbnNlIikpDQpkaWY8LWFzLm51bWVyaWMoZmluYWxuaV9scmdlLnRlc3QkZGVmYXVsdC55KQ0KDQphdXJvYy4xLnByZWQ8LWF1YyggZGlmLG1vZGVsMS5wcmVkKQ0KYXVyb2MuMi5wcmVkPC1hdWMoIGRpZixtb2RlbDIucHJlZCkNCmMoYXVyb2MuMS5wcmVkLGF1cm9jLjIucHJlZCkNCg0KYGBgDQoNCg0KDQpbXjNdOiBWaWRpIFJhdGluZyBNb2RlbHMgYW5kIFZhbGlkYXRpb24gLSAgT2VzdGVycmVpY2hpc2NoZSBOYXRpb25hbGJhbmsgKE9lTkIpLiAgDQpbXjRdOiBIYXlkZW4sIEUuLCAmIFBvcmF0aCwgRC4gKDIwMTEpLiBTdGF0aXN0aWNhbCBNZXRob2RzIHRvIERldmVsb3AgUmF0aW5nIE1vZGVscy4gSW4gQi4gRW5nZWxtYW5uLCBhbmQgUi4gUmF1aG1laWVyIChFZHMuKSwgVGhlIEJhc2VsIElJIFJpc2sgUGFyYW1ldGVyczogRXN0aW1hdGlvbiwgVmFsaWRhdGlvbiwgU3RyZXNzIFRlc3Rpbmcg4oCTIHdpdGggQXBwbGljYXRpb25zIHRvIExvYW4gUmlzayBNYW5hZ2VtZW50IChwcC4gMeKAkzEyKS4gTmV3IFlvcms6IFNwcmluZ2VyLiAgDQpbXjVdOiBEZXZlbG9waW5nLCBWYWxpZGF0aW5nIGFuZCBVc2luZyBJbnRlcm5hbCBSYXRpbmdzIC0gRGUgTGF1cmVudGlzDQpbXjZdOiBDcmVkaXQgUmlzayBNb2RlbGluZyB1c2luZyBFeGNlbCBhbmQgVkJBLCAybmQgRWRpdGlvbiAtIEd1bnRlciBMw7ZlZmZsZXIsIFBldGVyIE4uIFBvc2NoLg0KW143XTogVGhlIEJhc2VsIElJIFJpc2sgUGFyYW1ldGVyczogRXN0aW1hdGlvbiwgVmFsaWRhdGlvbiwgU3RyZXNzIFRlc3Rpbmcg4oCTIHdpdGggQXBwbGljYXRpb25zIHRvIExvYW4gUmlzayBNYW5hZ2VtZW50LCBDaGFwdGVyIDMuIE5ldyBZb3JrOiBTcHJpbmdlci4NClteOF06IENyZWRpdCBSaXNrIFNjb3JlY2FyZHM6IERldmVsb3BpbmcgYW5kIEltcGxlbWVudGluZyBJbnRlbGxpZ2VudCBDcmVkaXQgU2NvcmluZywgYnkgTmFlZW0gU2lkZGlxaSANCg0KDQpgYGB7cn0NCm15LnZhcnMgPC0gZmluYWxuaV9scmdlIyBhIG1hdHJpeCB3aXRoIHlvdXIgMTQgZGlmZmVyZW50IGVudmlyb25tZW50YWwgdmFyaWFibGVzDQpteS52YXJzLnRlc3QgPC0gZmluYWxuaV9scmdlLnRlc3QjIGEgbWF0cml4IHdpdGggeW91ciAxNCBkaWZmZXJlbnQgZW52aXJvbm1lbnRhbCB2YXJpYWJsZXMNCg0KbmFtZXMobXkudmFycylbYygxLDIsNCldPC1jKCJSaWdvcm96bmlfcmFjaW9fcmVkdWtvdmFuZV9tb25ldGFybmVfbGlrdmlkbm9zdGkiLCJSYWNpb19ub3ZjYW5lX2xpa3ZpZG5vc3RpIiwiUmFjaW9fcG9rcmljYV9rYW1hdGFfemFyYWRvbV9wcmVfa2FtYXRhX2lfcG9yZXphIikNCm5hbWVzKG15LnZhcnMudGVzdClbYygxLDIsNCldPC1jKCJSaWdvcm96bmlfcmFjaW9fcmVkdWtvdmFuZV9tb25ldGFybmVfbGlrdmlkbm9zdGkiLCJSYWNpb19ub3ZjYW5lX2xpa3ZpZG5vc3RpIiwiUmFjaW9fcG9rcmljYV9rYW1hdGFfemFyYWRvbV9wcmVfa2FtYXRhX2lfcG9yZXphIikNCg0KbXkudmFycyRkZWZhdWx0Lnk9TlVMTA0KDQpudmFyPC1uY29sKG15LnZhcnMpDQoNCiNjb2xuYW1lcyhteS52YXJzKSA8LSBwYXN0ZSgidmFyIiwgMTpudmFyLCBzZXA9IiIpICMgYWRkIHJvdyBuYW1lcyAidmFyMSIgLSAidmFyMTQiDQpteS5ncmFkLmRhdGEgPC0gMTpudmFyDQpzdW0udmFycyA8LSB2ZWN0b3IoKQ0KYXVjLnAgPC0gdmVjdG9yKCkNCmF1Yy5wcmVkPC12ZWN0b3IoKQ0KY29tYi5tYXQgPC0gbWF0cml4KG51bWVyaWMoMCksIG5yb3c9bnZhciwgbmNvbD0wKSAjIGluaXRpYWxpc2UgdGhlIG1hdHJpeCBjb250YWluaW5nIGFsbCBjb21iaW5hdGlvbnMNCmRpZjwtYXMubnVtZXJpYyhteS52YXJzLnRlc3QkZGVmYXVsdC55KQ0KDQoNCmZvciAoIGkgaW4gMTpudmFyICkgeyAjIGdlbmVyYXRlIGFuZCBzdG9yZSBhbGwgcG9zc2libGUgY29tYmluYXRpb24gb2Ygc3VtcyBvZiB0aGUgMTQgdmFyaWFibGVzDQogIA0KICB0Lm1hdCA8LSBjb21ibihteS5ncmFkLmRhdGEsIG09aSkNCiAgDQogIGNvbWIubWF0IDwtIGNiaW5kKGNvbWIubWF0LCByYmluZCh0Lm1hdCwgbWF0cml4KE5BLCBuY29sPWRpbSh0Lm1hdClbMl0gLCBucm93PW52YXItaSkpKQ0KfQ0KDQpjb2xubXM8LWNvbG5hbWVzKG15LnZhcnMpDQpteS52YXJzJGRlZmF1bHQueT1maW5hbG5pX2xyZ2UkZGVmYXVsdC55DQoNCm51bS5vZi52YXJzIDwtIGFwcGx5KGFzLmRhdGEuZnJhbWUoY29tYi5tYXQpLGMoMikNCiAgICAgICAgICAgICAgICAgICAgICAsIGZ1bmN0aW9uKHgpIHsNCiAgICAgICAgICAgICAgICAgICAgICBzdW0oYXMubnVtZXJpYyghaXMubmEoeCkpKQ0KICAgICAgICAgICAgICAgICAgICAgIH0pDQoNCmZvciAoIGogaW4gMTpkaW0oY29tYi5tYXQpWzJdICkgeyAjIGNhbGN1bGF0ZSBhbmQgc3RvcmUgdGhlIFIyIGZvciBhbGwgY29tYmluYXRpb25zDQogIA0KICAjc3VtLnZlYyA8LSByb3dTdW1zKG15LnZhcnNbLCBjb21iLm1hdFssIGpdXSwgbmEucm09VFJVRSkNCiNicm93c2VyKCkNCiAgc3VtLnZhcnNbal0gPC0gcGFzdGUoIGNvbG5tc1tjKG5hLm9taXQoY29tYi5tYXRbLCBqXSkpXSwgDQogICAgY29sbGFwc2U9IisiKQ0KICByZWxhY2lqYT1hcy5mb3JtdWxhKHBhc3RlKCJkZWZhdWx0LnkgfiAiLHN1bS52YXJzW2pdLHNlcCA9ICIiKSkNCiAgbW9kZWwgPSBzcGVlZGdsbShyZWxhY2lqYSwNCiAgICAgICAgICAgICAgICAgICBkYXRhID0gbXkudmFycywNCiAgICAgICAgICAgICAgICAgICB5PVRSVUUsDQogICAgICAgICAgICAgICAgICAgZml0dGVkID0gVFJVRSwNCiAgICAgICAgICAgICAgICAgICBmYW1pbHkgPSBiaW5vbWlhbChsaW5rID0gImxvZ2l0IikpDQojaWYoaj09MTMpIGJyb3dzZXIoKQ0KICBtb2RlbC5kYXRhLmZyYW1lPWRhdGEuZnJhbWUoZml0PWZpdHRlZC52YWx1ZXMobW9kZWwpLCBkaWY9bW9kZWwkeSkNCiAgYXVjLnBbal0gPC0gYXVjX3JvYyhhcy5udW1lcmljKG1vZGVsLmRhdGEuZnJhbWUkZml0KSxhcy5udW1lcmljKG1vZGVsLmRhdGEuZnJhbWUkZGlmKSkNCiAgDQogIG1vZGVsLnByZWQ8LWFzLm51bWVyaWMocHJlZGljdChtb2RlbCwgbmV3ZGF0YSA9bXkudmFycy50ZXN0LCB0eXBlID0gInJlc3BvbnNlIikpDQogIGF1Yy5wcmVkW2pdPC1hdWNfcm9jKCBtb2RlbC5wcmVkLGRpZikNCiAgDQogIGlmKGogJWluJSByb3VuZChzZXEoZnJvbT0xLCB0bz1kaW0oY29tYi5tYXQpWzJdLGxlbmd0aC5vdXQgPSAxMDApKSkgcHJpbnQoai9kaW0oY29tYi5tYXQpWzJdKQ0KICAjcHJpbnQoaikNCiAgDQp9DQoNCg0KDQpyZXN1bHQuZnJhbWUgPC0gZGF0YS5mcmFtZShjb21iaW5hdGlvbj1zdW0udmFycywgYXVjLnA9YXVjLnAsIGF1Yy50ZXN0PWF1Yy5wcmVkLG51bV9vZl92YXJzPW51bS5vZi52YXJzKQ0KDQpyZXN1bHQuZnJhbWUuc29ydGVkIDwtIHJlc3VsdC5mcmFtZVtvcmRlcigtYXVjLnByZWQsLWF1Yy5wLC1udW0ub2YudmFycyksIF0NCg0KICBoZWFkKHJlc3VsdC5mcmFtZS5zb3J0ZWRbcmVzdWx0LmZyYW1lLnNvcnRlZCRhdWMudGVzdD4wLjc1ICYgcmVzdWx0LmZyYW1lLnNvcnRlZCRhdWMucD4wLjc1ICYgcmVzdWx0LmZyYW1lLnNvcnRlZCRudW1fb2ZfdmFycz09NixdLCBuPTEwMCkgIyB0aGUgMTAgImJlc3QiIGNvbWJpbmF0aW9ucw0KYGBgDQoNCg0KS29uYWNubyBiaXJhbW8gb3Z1IGZvcm11bHU6ICANCg0KDQogZ2xtKGZvcm11bGEgPWRlZmF1bHQueX5gUmFjaW9fbm92Y2FuZV9saWt2aWRub3N0aV8oQ2FzaF9yYXRpbylgK1N0ZXBlbl96YWR1emVub3N0aStHb3Rvdmluc2tpX2Npa2x1c18xK1ZyZW1lX25hcGxhdGVfcG90cmF6aXZhbmphK1N0b3BhX3ByaW5vc2FfbmFfc29wc3R2ZW5pX2thcGl0YWxfcHJlX29wb3Jleml2YW5qYStDZW5hX3R1ZGppaF9penZvcmFfc3JlZHN0YXZhLCBmYW1pbHkgPSBiaW5vbWlhbChsaW5rID0gImxvZ2l0IiksIA0KICAgIGRhdGEgPSBmaW5hbG5pX2xyZ2UpYCAgDQpfX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fXw0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQo=